Merge pull request #1 from shackbarth/keith1
authorkrauseo <krauseo@users.noreply.github.com>
Fri, 12 Sep 2014 16:17:28 +0000 (12:17 -0400)
committerkrauseo <krauseo@users.noreply.github.com>
Fri, 12 Sep 2014 16:17:28 +0000 (12:17 -0400)
Keith1

327 files changed:
.gitignore
.travis.yml
README.md
RELEASE.md [deleted file]
enyo-client/application/enyo
enyo-client/application/source/en/strings.js
enyo-client/application/source/ext/datasource.js
enyo-client/application/source/ext/session.js
enyo-client/application/source/models/address.js
enyo-client/application/source/models/incident.js
enyo-client/application/source/models/invoice.js
enyo-client/application/source/models/sales_order.js
enyo-client/application/source/models/site.js
enyo-client/application/source/preliminaries.js
enyo-client/application/source/startup.js
enyo-client/application/source/views/list.js
enyo-client/application/source/views/list_relations_box.js
enyo-client/application/source/views/workspace.js
enyo-client/application/source/widgets/characteristics.js
enyo-client/application/source/widgets/checkbox.js
enyo-client/application/source/widgets/combobox.js
enyo-client/application/source/widgets/money.js
enyo-client/application/source/widgets/number.js
enyo-client/application/source/widgets/parameter.js
enyo-client/application/source/widgets/relation.js
enyo-client/database/orm/models/customer.json
enyo-client/database/orm/models/employee.json
enyo-client/database/orm/models/site.json
enyo-client/database/orm/models/sys.json
enyo-client/database/orm/models/url.json
enyo-client/database/source/add_admin_role.sql [new file with mode: 0644]
enyo-client/database/source/grant_roles.sql [new file with mode: 0644]
enyo-client/database/source/manifest.js
enyo-client/database/source/populate_data.js [new file with mode: 0644]
enyo-client/database/source/priv.sql [deleted file]
enyo-client/database/source/public/tables/priv.sql [new file with mode: 0644]
enyo-client/database/source/update_version.sql
enyo-client/database/source/xm/javascript/item_site.sql
enyo-client/database/source/xt/functions/grant_role_priv.sql
enyo-client/database/source/xt/views/itemsiteinfo.sql
enyo-client/extensions/source/billing/client/core.js
enyo-client/extensions/source/crm/client/core.js
enyo-client/extensions/source/crm/client/en/strings.js
enyo-client/extensions/source/crm/client/postbooks.js
enyo-client/extensions/source/crm/client/widgets/chart.js
enyo-client/extensions/source/oauth2/client/core.js
enyo-client/extensions/source/oauth2/client/en/strings.js
enyo-client/extensions/source/oauth2/client/models/oauth2.js
enyo-client/extensions/source/oauth2/client/views/workspace.js
enyo-client/extensions/source/project/client/core.js
enyo-client/extensions/source/purchasing/client/core.js
enyo-client/extensions/source/purchasing/client/en/strings.js
enyo-client/extensions/source/purchasing/client/widgets/relation.js
enyo-client/extensions/source/sales/client/core.js
enyo-client/extensions/source/sales/client/en/strings.js
enyo-client/extensions/source/sales/client/postbooks.js
enyo-client/extensions/source/sales/client/views/workspace.js
enyo-client/extensions/source/sales/client/widgets/chart.js
foundation-database/manifest.js
foundation-database/postbooks_demo_data.sql
foundation-database/public/functions/assessfinancecharge.sql
foundation-database/public/functions/avgcost.sql
foundation-database/public/functions/balanceitemsite.sql
foundation-database/public/functions/bankreconciliation.sql [new file with mode: 0644]
foundation-database/public/functions/calcinvoiceamt.sql
foundation-database/public/functions/calcsalesorderamt.sql
foundation-database/public/functions/convertquote.sql
foundation-database/public/functions/convertquotetoinvoice.sql
foundation-database/public/functions/copyitemsite.sql
foundation-database/public/functions/deleteitemsite.sql
foundation-database/public/functions/detailednnqoh.sql
foundation-database/public/functions/detailedqoh.sql
foundation-database/public/functions/distributeitemlocseries.sql
foundation-database/public/functions/distributetolocations.sql
foundation-database/public/functions/explodekit.sql
foundation-database/public/functions/fetchnextchecknumber.sql
foundation-database/public/functions/getsoitemstatus.sql
foundation-database/public/functions/importbankreccleared.sql [new file with mode: 0644]
foundation-database/public/functions/indentedwo.sql
foundation-database/public/functions/indentedwomatl.sql
foundation-database/public/functions/initialdistribution.sql
foundation-database/public/functions/itemcost.sql
foundation-database/public/functions/iteminventoryuominuse.sql
foundation-database/public/functions/itemipsprice.sql
foundation-database/public/functions/postbankreconciliation.sql
foundation-database/public/functions/postcashreceipt.sql
foundation-database/public/functions/postcheck.sql
foundation-database/public/functions/postcounttag.sql
foundation-database/public/functions/postcounttaglocation.sql
foundation-database/public/functions/postinvtrans.sql
foundation-database/public/functions/qtyatlocation.sql [new file with mode: 0644]
foundation-database/public/functions/qtyavailable.sql
foundation-database/public/functions/qtynetable.sql [new file with mode: 0644]
foundation-database/public/functions/releasepr.sql [new file with mode: 0644]
foundation-database/public/functions/relocateinventory.sql
foundation-database/public/functions/reopenbankreconciliation.sql
foundation-database/public/functions/setnextchecknumber.sql
foundation-database/public/functions/sufficientinventorytoshipitem.sql
foundation-database/public/functions/thawitemsite.sql
foundation-database/public/functions/togglebankreccleared.sql
foundation-database/public/functions/updatestdcost.sql
foundation-database/public/functions/woinvavail.sql
foundation-database/public/functions/woinvavailmatl.sql
foundation-database/public/patches/fixflcol.sql [new file with mode: 0644]
foundation-database/public/tables/bankrecimport.sql [new file with mode: 0644]
foundation-database/public/tables/bankrecimport.xml [new file with mode: 0644]
foundation-database/public/tables/checkhead.sql [new file with mode: 0644]
foundation-database/public/tables/itemsite.sql [new file with mode: 0644]
foundation-database/public/tables/location.sql
foundation-database/public/tables/metasql/apOpenItems-selectedpayments.mql
foundation-database/public/tables/metasql/apOpenItems-selectpayments.mql
foundation-database/public/tables/metasql/bankrec-clearedbalance.mql
foundation-database/public/tables/metasql/bankrecHistory-reconciled.mql
foundation-database/public/tables/metasql/bookings-detail.mql
foundation-database/public/tables/metasql/briefEarnedCommission-detail.mql
foundation-database/public/tables/metasql/briefSalesHistory-detail.mql
foundation-database/public/tables/metasql/countTag-detail.mql
foundation-database/public/tables/metasql/distributeInventory-locations.mql
foundation-database/public/tables/metasql/inventoryAvailability-byCustOrSO.mql
foundation-database/public/tables/metasql/inventoryAvailability-general.mql
foundation-database/public/tables/metasql/inventoryLocator-detail.mql
foundation-database/public/tables/metasql/invoices-detail.mql
foundation-database/public/tables/metasql/itemPricingSchedule-detail.mql
foundation-database/public/tables/metasql/mrpDetail-detail.mql
foundation-database/public/tables/metasql/opensalesorders-detail.mql
foundation-database/public/tables/metasql/orderActivityByProject-detail.mql
foundation-database/public/tables/metasql/pendingAvailability-detail.mql
foundation-database/public/tables/metasql/pricelist-detail.mql
foundation-database/public/tables/metasql/projects-detail.mql
foundation-database/public/tables/metasql/projects-detail_nohierarchy.mql
foundation-database/public/tables/metasql/purchase-purchaserequests.mql
foundation-database/public/tables/metasql/qoh-detail.mql
foundation-database/public/tables/metasql/reorderExceptionsByPlannerCode-detail.mql
foundation-database/public/tables/metasql/runningAvailability-detail.mql
foundation-database/public/tables/metasql/salesHistory-detail.mql
foundation-database/public/tables/metasql/salesOrderItems-list.mql
foundation-database/public/tables/metasql/substituteAvailability-detail.mql
foundation-database/public/tables/metasql/summarizedSalesHistory-detail.mql
foundation-database/public/tables/metasql/unbalancedQOHByClassCode-detail.mql
foundation-database/public/tables/metasql/updatePrices-update.mql
foundation-database/public/tables/metric.sql
foundation-database/public/tables/report/BankrecHistory.xml
foundation-database/public/tables/report/BriefEarnedCommissions.xml
foundation-database/public/tables/report/BriefSalesHistory.xml
foundation-database/public/tables/report/EarnedCommissions.xml
foundation-database/public/tables/report/InventoryAvailability.xml
foundation-database/public/tables/report/InventoryAvailabilityByCustomerType.xml
foundation-database/public/tables/report/InventoryAvailabilityBySalesOrder.xml
foundation-database/public/tables/report/InventoryAvailabilityBySourceVendor.xml
foundation-database/public/tables/report/ItemCostsByClassCode.xml
foundation-database/public/tables/report/PackingList-Shipment.xml
foundation-database/public/tables/report/ReorderExceptionsByPlannerCode.xml
foundation-database/public/tables/report/RunningAvailability.xml
foundation-database/public/tables/report/SalesHistory.xml
foundation-database/public/tables/report/SubstituteAvailabilityByRootItem.xml
foundation-database/public/tables/setVersion.sql [new file with mode: 0644]
foundation-database/public/trigger_functions/coitem.sql
foundation-database/public/trigger_functions/itemsite.sql
foundation-database/public/trigger_functions/location.sql
foundation-database/public/views/docinfo.sql
foundation-database/public/views/saleshistory.sql
foundation-database/public/views/saleshistorymisc.sql
lib/backbone-x/source/model_mixin.js
lib/backbone-x/source/package.js
lib/backbone-x/source/router.js [new file with mode: 0644]
lib/enyo-x/enyo
lib/enyo-x/source/app.js
lib/enyo-x/source/core.js
lib/enyo-x/source/less/address.less
lib/enyo-x/source/less/characteristics.less [deleted file]
lib/enyo-x/source/less/dashboard.less
lib/enyo-x/source/less/grid.less
lib/enyo-x/source/less/list.less
lib/enyo-x/source/less/picker.less
lib/enyo-x/source/less/pullout.less
lib/enyo-x/source/less/relations.less
lib/enyo-x/source/less/screen.less
lib/enyo-x/source/less/widgets.less [deleted file]
lib/enyo-x/source/less/workspace.less
lib/enyo-x/source/stylesheets/screen.css
lib/enyo-x/source/views/child_workspace.js
lib/enyo-x/source/views/grid_box.js
lib/enyo-x/source/views/list.js
lib/enyo-x/source/views/list_base.js
lib/enyo-x/source/views/list_relations_editor_box.js
lib/enyo-x/source/views/module_container.js
lib/enyo-x/source/views/workspace.js
lib/enyo-x/source/widgets/characteristics.js
lib/enyo-x/source/widgets/checkbox.js
lib/enyo-x/source/widgets/combobox.js
lib/enyo-x/source/widgets/date.js
lib/enyo-x/source/widgets/file_input.js
lib/enyo-x/source/widgets/input.js
lib/enyo-x/source/widgets/number.js
lib/enyo-x/source/widgets/number_spinner.js
lib/enyo-x/source/widgets/parameter.js
lib/enyo-x/source/widgets/picker.js
lib/enyo-x/source/widgets/relation.js
lib/enyo-x/source/widgets/text_area.js
lib/enyo-x/source/widgets/toggle_button.js
lib/orm/LICENSE.txt [deleted file]
lib/orm/source/create_sys_schema.sql
lib/orm/source/create_xm_schema.sql
lib/orm/source/manifest.js
lib/orm/source/xt/functions/add_comment_type.sql [new file with mode: 0644]
lib/orm/source/xt/functions/create_schema.sql [new file with mode: 0644]
lib/orm/source/xt/javascript/discovery.sql
lib/orm/source/xt/javascript/schema.sql
node-datasource/lib/ext/models.js
node-datasource/main.js
node-datasource/oauth2/oauth2.js
node-datasource/routes/analysis.js [deleted file]
node-datasource/routes/app.js
node-datasource/routes/auth.js
node-datasource/routes/install_extension.js [new file with mode: 0644]
node-datasource/routes/routes.js
node-datasource/views/app.ejs
node-datasource/views/debug.ejs
node-datasource/views/login.ejs
node-datasource/views/login/stylesheets/screen.css
node-datasource/xt/xt.js
npm-shrinkwrap.json
package.json
scripts/GENERATE_SPECS_README.md [deleted file]
scripts/build_app.js
scripts/explode_manifest.js
scripts/generateDocs.sh [deleted file]
scripts/generateSpecs.sh [deleted file]
scripts/install_bi.sh [deleted file]
scripts/install_xtuple.sh
scripts/jsdoc-user.conf.json [deleted file]
scripts/jsdoc.conf.json [deleted file]
scripts/jsdoc_README.md [deleted file]
scripts/jsdoc_spec_README.md [deleted file]
scripts/jsdoc_spec_user_README.md [deleted file]
scripts/lib/build_all.js
scripts/lib/build_client.js
scripts/lib/build_database.js
scripts/lib/build_database_util.js [deleted file]
scripts/lib/build_dictionary.js
scripts/lib/util/convert_specialized.js [new file with mode: 0644]
scripts/lib/util/default_extensions.js [new file with mode: 0644]
scripts/lib/util/init_database.js [new file with mode: 0644]
scripts/lib/util/inspect_database.js [new file with mode: 0644]
scripts/lib/util/process_manifest.js [new file with mode: 0644]
scripts/lib/util/send_to_database.js [new file with mode: 0644]
scripts/lib/util/unregister.js [new file with mode: 0644]
scripts/release_build.sh
scripts/start_bi.sh [deleted file]
scripts/stop_bi.sh [deleted file]
scripts/templates/README.md [deleted file]
scripts/templates/xtuple/README.md [deleted file]
scripts/templates/xtuple/publish.js [deleted file]
scripts/templates/xtuple/static/scripts/linenumber.js [deleted file]
scripts/templates/xtuple/static/scripts/prettify/Apache-License-2.0.txt [deleted file]
scripts/templates/xtuple/static/scripts/prettify/lang-css.js [deleted file]
scripts/templates/xtuple/static/scripts/prettify/prettify.js [deleted file]
scripts/templates/xtuple/static/styles/jsdoc-default.css [deleted file]
scripts/templates/xtuple/static/styles/prettify-jsdoc.css [deleted file]
scripts/templates/xtuple/static/styles/prettify-tomorrow.css [deleted file]
scripts/templates/xtuple/tmpl/container.tmpl [deleted file]
scripts/templates/xtuple/tmpl/details.tmpl [deleted file]
scripts/templates/xtuple/tmpl/example.tmpl [deleted file]
scripts/templates/xtuple/tmpl/examples.tmpl [deleted file]
scripts/templates/xtuple/tmpl/exceptions.tmpl [deleted file]
scripts/templates/xtuple/tmpl/layout.tmpl [deleted file]
scripts/templates/xtuple/tmpl/mainpage.tmpl [deleted file]
scripts/templates/xtuple/tmpl/members.tmpl [deleted file]
scripts/templates/xtuple/tmpl/method.tmpl [deleted file]
scripts/templates/xtuple/tmpl/params.tmpl [deleted file]
scripts/templates/xtuple/tmpl/properties.tmpl [deleted file]
scripts/templates/xtuple/tmpl/returns.tmpl [deleted file]
scripts/templates/xtuple/tmpl/source.tmpl [deleted file]
scripts/templates/xtuple/tmpl/tutorial.tmpl [deleted file]
scripts/templates/xtuple/tmpl/type.tmpl [deleted file]
scripts/templates/xtuple_specs/README.md [deleted file]
scripts/templates/xtuple_specs/publish.js [deleted file]
scripts/templates/xtuple_specs/static/scripts/linenumber.js [deleted file]
scripts/templates/xtuple_specs/static/scripts/prettify/Apache-License-2.0.txt [deleted file]
scripts/templates/xtuple_specs/static/scripts/prettify/lang-css.js [deleted file]
scripts/templates/xtuple_specs/static/scripts/prettify/prettify.js [deleted file]
scripts/templates/xtuple_specs/static/styles/jsdoc-default.css [deleted file]
scripts/templates/xtuple_specs/static/styles/prettify-jsdoc.css [deleted file]
scripts/templates/xtuple_specs/static/styles/prettify-tomorrow.css [deleted file]
scripts/templates/xtuple_specs/tmpl/container.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/details.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/example.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/examples.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/exceptions.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/layout.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/mainpage.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/members.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/method.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/params.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/properties.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/returns.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/source.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/tutorial.tmpl [deleted file]
scripts/templates/xtuple_specs/tmpl/type.tmpl [deleted file]
scripts/xml/distribution_install.xml
scripts/xml/distribution_package.xml
scripts/xml/postbooks_package.xml
scripts/xml/xtmfg_install.xml
scripts/xml/xtmfg_package.xml
test/build/build_app.js
test/database/bankrec.js [new file with mode: 0644]
test/database/gotchas.js
test/database/joins.js
test/extensions/all/configure.js
test/extensions/all/grid_box.js
test/extensions/all/workspace.js
test/extensions/core/date.js
test/extensions/crm/characteristics.js
test/extensions/sales/sales_order_workspace.js
test/lib/crud.js
test/lib/runner_engine.js
test/lib/smoke.js
test/lib/test_runner.js
test/lib/zombie_auth.js
test/models/credit_card.js [deleted file]
test/specs/country.js
test/specs/credit_card.js [deleted file]
test/specs/customer.js
test/specs/incident.js
test/specs/invoice.js
test/specs/return.js
test/specs/site.js

index 1892508..76887af 100644 (file)
@@ -1,3 +1,4 @@
+*.log
 *.DS_Store
 *.sw*
 *~
index b6af55e..10dcc2b 100644 (file)
@@ -1,6 +1,6 @@
 language: node_js
 node_js:
-  - "0.8"
+  - "0.10"
 
 install:
   - "bash scripts/install_xtuple.sh -ipn"
@@ -12,6 +12,10 @@ before_script:
   - "cd .."
 
 script:
-  - "npm run-script test"
   - "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 879f68f..ed58ba9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -38,10 +38,22 @@ Fork us, take a test drive with our [free trial](http://www.xtuple.com/free-tria
 file a github issue. 
 If you want to be a contributor and are looking for a place to
 make your mark, we're keeping a list of issues that are 
-[fair game](https://github.com/xtuple/xtuple/issues?labels=fair+game) 
+[fair game](https://github.com/xtuple/xtuple/labels/fair%20game)
 to pick off and provide
 a convenient, well-documented starting point into our project.
 
+In the month of August, we will be running haxTuple 2014. As in previous incarnations, 
+we will open up our bug-shooting derby for the Qt client to our community, with prizes 
+for the most effective bugsquashers! In this year's event, we will also introduce our 
+new technologies by opening up our webapp for haxxing. Those who write the best 
+JavaScript extensions or REST clients will get prizes. More details 
+[here](https://github.com/xtuple/xtuple/wiki/haxTuple-2014).
+
+Also, don't miss the xTuple event of the year! 
+[xTupleCon 2014](http://www.xtuple.com/xtuple-conference-2014)
+is going to be held October 13-18 in Norfolk, VA. With six days of events and a kickoff
+speech by Steve Wozniak, it promises to the be the biggest xTupleCon yet.
+
 ### Installing this project
 
 The best way to start coding on our stack is to use our
@@ -49,11 +61,12 @@ The best way to start coding on our stack is to use our
 
 ### Release Notes
 
-View the [Release Notes](RELEASE.md) to see a change log.
+View the [Release Notes](https://github.com/xtuple/xtuple-documentation/tree/master/release-notes) 
+to see a change log.
 
 ### Additional Resources
-
-  * [Setting up a non-development demo environment](https://github.com/xtuple/xtuple/wiki/How-to-set-up-xTuple)
   * [Building an Extension Tutorial](https://github.com/xtuple/xtuple-extensions/blob/master/docs/TUTORIAL.md)
-  * [API documentation](http://xtuple.com/jsdoc)
   * [Developer Wiki](https://github.com/xtuple/xtuple/wiki)
+  * xTuple U [Tutorial Videos](https://github.com/xtuple/xtuple/wiki/Tutorial-Videos)
+  * [API documentation](http://xtuple.github.io/api/current)
+  * [Setting up a non-development demo environment](https://github.com/xtuple/xtuple/wiki/How-to-set-up-xTuple)
diff --git a/RELEASE.md b/RELEASE.md
deleted file mode 100644 (file)
index 14c7107..0000000
+++ /dev/null
@@ -1,1820 +0,0 @@
-4.5.0 (Beta 2014/05/22, Final 2014/06/06)
-==================
-
-Critical deployment changes
----------------------------
-- If you installed 4.5.0 beta on your database, and want to upgrade it from the beta
-  to 4.5.0 final, you'll need to update the column type of the `taxpay.taxpay_id`
-  column from `integer` to `serial`.
-
-  If you're going straight to 4.5 final, you don't have to worry about this.
-
-  In general, of course, it's best not to put your production database through a beta.
-  You can pilot on a beta, but then to get to the final, you should pilot straight
-  from your production version to the final.
-
-
-Features and bugfixes
----------------------
-TODO: document
-
-
-4.4.1 (2014/05/09)
-==================
-
-Features and bugfixes
----------------------
-TODO: document
-
-
-
-4.4.0 (2014/04/04)
-==================
-
-Critical deployment changes
----------------------------
-- The `oauth2` extension is now part of core. If you had its routes referenced
-  in your `config.js`'s `extensionRoutes` attribute, you should remove it.
-- Make sure you `git submodule update --init --recursive`
-
-Features and bugfixes
----------------------
-- Completed 
-  issue #[22131](http://www.xtuple.org/xtincident/view/bugs/22131) 
-  _Drilldown support in analytic charts_ 
-- Implemented 
-  issue #[22656](http://www.xtuple.org/xtincident/view/bugs/22656) 
-  _Refactor panels and change visual presentation_ 
-- Fixed 
-  issue #[23012](http://www.xtuple.org/xtincident/view/bugs/23012) 
-  _Roles don't pull in translations_ 
-- Fixed 
-  issue #[23028](http://www.xtuple.org/xtincident/view/bugs/23028) 
-  _install_bi.sh NEEDS path to config file option_ 
-- Implemented 
-  issue #[23046](http://www.xtuple.org/xtincident/view/bugs/23046) 
-  _Update MW to create dynamic class id for enyo list items_ 
-- Implemented 
-  issue #[23086](http://www.xtuple.org/xtincident/view/bugs/23086) 
-  _Unified database build_ 
-- Fixed 
-  issue #[23094](http://www.xtuple.org/xtincident/view/bugs/23094) 
-  _Name/Date Overlap on Sales Order_ 
-- Implemented 
-  issue #[23108](http://www.xtuple.org/xtincident/view/bugs/23108) 
-  _Optimize XT.Data's buildClause to use joins on underlying tables and views_ 
-- Implemented 
-  issue #[23168](http://www.xtuple.org/xtincident/view/bugs/23168) 
-  _move OAUTH2 extension to core_ 
-- Fixed 
-  issue #[23183](http://www.xtuple.org/xtincident/view/bugs/23183) 
-  _*Converting sales order_ 
-- Fixed 
-  issue #[23260](http://www.xtuple.org/xtincident/view/bugs/23260) 
-  _Converting Quote to SO does not work_ 
-
-
-
-1.8.1 (2014/03/12)
-==================
-
-Features and bugfixes
----------------------
-- Fixed 
-  issue #[22518](http://www.xtuple.org/xtincident/view/bugs/22518) 
-  _Post Production, Issue Materials, Enter Receipt, Post Receipt should update workflows_ 
-- Fixed 
-  issue #[22526](http://www.xtuple.org/xtincident/view/bugs/22526) 
-  _Add support to return materials from a Work Order_ 
-- Fixed 
-  issue #[22668](http://www.xtuple.org/xtincident/view/bugs/22668) 
-  _Can not save filters in mobile_ 
-- Fixed 
-  issue #[22746](http://www.xtuple.org/xtincident/view/bugs/22746) 
-  _Long project descriptions bleed into adjacent columns_ 
-- Implemented 
-  issue #[22782](http://www.xtuple.org/xtincident/view/bugs/22782) 
-  _Print pack list_ 
-- Fixed 
-  issue #[22901](http://www.xtuple.org/xtincident/view/bugs/22901) 
-  _Incident plus versions are not showing up_ 
-- Fixed 
-  issue #[23010](http://www.xtuple.org/xtincident/view/bugs/23010) 
-  _Sales Type workflow missing defaults_ 
-- Fixed 
-  issue #[23013](http://www.xtuple.org/xtincident/view/bugs/23013) 
-  _Due date does not calculate on Sales Order Worflow_ 
-- Fixed 
-  issue #[23018](http://www.xtuple.org/xtincident/view/bugs/23018) 
-  _Opportunities do not have default Currency_ 
-
-
-1.8.0 (2014/03/07)
-==================
-
-Features and bugfixes
----------------------
- Implemented 
-  issue #[19037](http://www.xtuple.org/xtincident/view/bugs/19037) 
-  _Summary on project_ 
-- Implemented 
-  issue #[21508](http://www.xtuple.org/xtincident/view/bugs/21508) 
-  _Add support for basic Work Order transactions_ 
-- Implemented 
-  issue #[22078](http://www.xtuple.org/xtincident/view/bugs/22078) 
-  _Add support for Backflush on Post Production_ 
-- Implemented 
-  issue #[22079](http://www.xtuple.org/xtincident/view/bugs/22079) 
-  _Add support for Close Work Order on Post Production_ 
-- Implemented 
-  issue #[22237](http://www.xtuple.org/xtincident/view/bugs/22237) 
-  _Add support to print and email Invoices_ 
-- Implemented 
-  issue #[22241](http://www.xtuple.org/xtincident/view/bugs/22241) 
-  _Add support to print barcode Location labels_ 
-- Implemented 
-  issue #[22243](http://www.xtuple.org/xtincident/view/bugs/22243) 
-  _Add support to print Item barcode labels_ 
-- Implemented 
-  issue #[22442](http://www.xtuple.org/xtincident/view/bugs/22442) 
-  _CRM sales pipeline charts for dashboard_ 
-- Implemented 
-  issue #[22459](http://www.xtuple.org/xtincident/view/bugs/22459) 
-  _Barcode capture use-cases_ 
-- Implemented 
-  issue #[22461](http://www.xtuple.org/xtincident/view/bugs/22461) 
-  _Silent print from nodejs_ 
-- Implemented 
-  issue #[22534](http://www.xtuple.org/xtincident/view/bugs/22534) 
-  _Add support Inventory Availability to web client_ 
-- Implemented 
-  issue #[22577](http://www.xtuple.org/xtincident/view/bugs/22577) 
-  _Private extensions under test_ 
-- Implemented 
-  issue #[22638](http://www.xtuple.org/xtincident/view/bugs/22638) 
-  _Add inventory availability information to Sales Order_ 
-- Fixed 
-  issue #[22645](http://www.xtuple.org/xtincident/view/bugs/22645) 
-  _Internal server error on dogfood_ 
-- Fixed 
-  issue #[22651](http://www.xtuple.org/xtincident/view/bugs/22651) 
-  _Natural Key Not Found Error on Empty DB_ 
-- Implemented 
-  issue #[22669](http://www.xtuple.org/xtincident/view/bugs/22669) 
-  _Add support for automatic supply order creation on Sales Orders_ 
-- Implemented 
-  issue #[22689](http://www.xtuple.org/xtincident/view/bugs/22689) 
-  _Support for a second jsdoc template_ 
-- Fixed 
-  issue #[22728](http://www.xtuple.org/xtincident/view/bugs/22728) 
-  _*Configure list is blank_ 
-- Implemented 
-  issue #[22750](http://www.xtuple.org/xtincident/view/bugs/22750) 
-  _Add project type to project list_ 
-- Implemented 
-  issue #[22822](http://www.xtuple.org/xtincident/view/bugs/22822) 
-  _Add support to for planned order list_ 
-- Implemented 
-  issue #[22971](http://www.xtuple.org/xtincident/view/bugs/22971) 
-  _Get tutorial up to date_ 
-- Fixed 
-  issue #[22980](http://www.xtuple.org/xtincident/view/bugs/22980) 
-  _Optimizations for K+H database_ 
-
-1.7.2 (2014/02/24)
-==================
-
-Features and bugfixes
----------------------
-- Fixed
-  issue #[22754](http://www.xtuple.org/xtincident/view/bugs/22754)
-  _*DB log error is displayed on selecting to add a Bill of Operation Item for a new item_
-- Fixed
-  issue #[22755](http://www.xtuple.org/xtincident/view/bugs/22755) 
-  _* It is not possible to add a Bill of Material Item to a new item_ 
-- Fixed 
-  issue #[22793](http://www.xtuple.org/xtincident/view/bugs/22793) 
-  _Characteristics not showing up on Customer Workspace_ 
-- Implemented 
-  issue #[22829](http://www.xtuple.org/xtincident/view/bugs/22829) 
-  _Registration via Website appears broken_ 
-- Fixed 
-  issue #[22839](http://www.xtuple.org/xtincident/view/bugs/22839) 
-  _Mobile installation disrupts invoices out of qt_ 
-
-1.7.1 (2014/02/10)
-==================
-
-Features and bugfixes
----------------------
-- Fixed
-  issue #[22659](http://www.xtuple.org/xtincident/view/bugs/22659)
-  _Remove xt.obj inheritance to avoid backup column reordering_
-
-1.7.0 (2014/02/03)
-==================
-
-Features and bugfixes
----------------------
-
-- Implemented
-  issue #[22059](http://www.xtuple.org/xtincident/view/bugs/22059)
-  _Approve for billing and create invoice at time of shipping_
-- Implemented
-  issue #[22029](http://www.xtuple.org/xtincident/view/bugs/22029)
-  _Cash receipt on sales order_
-- Implemented
-  issue #[21229](http://www.xtuple.org/xtincident/view/bugs/21229)
-  _REST - Add support for a count query_
-- Implemented
-  issue #[22029](http://www.xtuple.org/xtincident/view/bugs/22029)
-  _Implement Cash Receipt on Sales Order_
-- Implemented
-  issue #[22059](http://www.xtuple.org/xtincident/view/bugs/22059)
-  _Implement Approve for Billing(select for billing)/Create Invoice at time of Shipping_
-- Implemented
-  issue #[22155](http://www.xtuple.org/xtincident/view/bugs/22155)
-  _Add support for Purchase Order_
-- Fixed
-  issue #[22181](http://www.xtuple.org/xtincident/view/bugs/22181)
-  _*Tax adjustment is not added to the Total Tax of an Invoice_
-- Implemented
-  issue #[22237](http://www.xtuple.org/xtincident/view/bugs/22237)
-  _Add support to print and email Invoices_
-- Implemented
-  issue #[22341](http://www.xtuple.org/xtincident/view/bugs/22341)
-  _Add support for Work Orders_
-- Fixed
-  issue #[22397](http://www.xtuple.org/xtincident/view/bugs/22397)
-  _*Unit Cost and Tax amount values are not displayed in the Invoice Line and Return Line screens_
-- Fixed
-  issue #[22398](http://www.xtuple.org/xtincident/view/bugs/22398)
-  _*Fractional Tax values are rounded in the Sales Order Line/Quote Line screen_
-- Fixed
-  issue #[22402](http://www.xtuple.org/xtincident/view/bugs/22402)
-  _itemIspPrice() requires site_id for markup pricing to to work_
-- Fixed
-  issue #[22436](http://www.xtuple.org/xtincident/view/bugs/22436)
-  _Faulty Transfer Order line item statuses_
-- Implemented
-  issue #[22498](http://www.xtuple.org/xtincident/view/bugs/22498)
-  _build 1.7.0 with 4.3 database_
-- Implemented
-  issue #[22500](http://www.xtuple.org/xtincident/view/bugs/22500)
-  _Barcode prefix/suffix should be configurable_
-- Fixed
-  issue #[22588](http://www.xtuple.org/xtincident/view/bugs/22588)
-  _Customers with Credit Warning gets Credit Hold error message_
-- Fixed
-  issue #[22622](http://www.xtuple.org/xtincident/view/bugs/22622)
-  _Workaround Pentaho roles problem_ 
-
-1.6.0 (2014/01/15)
-==================
-
-Critical deployment changes
----------------------------
-Mobile Client connections to Pentaho are no longer defined by biUrl and biServerUrl in config.js.  They are now defined
-by biServer and printServer.  See the details in:
-
-https://github.com/xtuple/xtuple/wiki/xTuple-Business-Intelligence
-
-Features and bugfixes
----------------------
-
-- Fixed
-  issue #[18338](http://www.xtuple.org/xtincident/view/bugs/18338)
-  _Error running merge contacts in dogfood_
-- Fixed
-  issue #[18401](http://www.xtuple.org/xtincident/view/bugs/18401)
-  _Relation autocompleter menu gets in the way_
-- Fixed
-  issue #[18505](http://www.xtuple.org/xtincident/view/bugs/18505)
-  _Advanced search panel is blank on iPad_
-- Fixed
-  issue #[18521](http://www.xtuple.org/xtincident/view/bugs/18521)
-  _Automatically-added comments have "admin" as the name_
-- Fixed
-  issue #[18635](http://www.xtuple.org/xtincident/view/bugs/18635)
-  _Creating a user account in the mobile client does not create a CRM Account_
-- Implemented
-  issue #[18637](http://www.xtuple.org/xtincident/view/bugs/18637)
-  _Extend "Personal" privilege methodology to any property that can be tied back to a UserAccount ID_
-- Fixed
-  issue #[18640](http://www.xtuple.org/xtincident/view/bugs/18640)
-  _error in CRM Acct Merge_
-- Fixed
-  issue #[18692](http://www.xtuple.org/xtincident/view/bugs/18692)
-  _List Relation Box should be disabled for new records_
-- Fixed
-  issue #[18695](http://www.xtuple.org/xtincident/view/bugs/18695)
-  _Comments don't work on iPad_
-- Fixed
-  issue #[18698](http://www.xtuple.org/xtincident/view/bugs/18698)
-  _iPad sorts strings as numbers_
-- Fixed
-  issue #[18699](http://www.xtuple.org/xtincident/view/bugs/18699)
-classes: "right"  _iPad does not scroll smoothly_
-- Fixed
-  issue #[18707](http://www.xtuple.org/xtincident/view/bugs/18707)
-  _Can't switch databases on iPad_
-- Fixed
-  issue #[18730](http://www.xtuple.org/xtincident/view/bugs/18730)
-  _Task number read only status is erratic_
-- Fixed
-  issue #[18731](http://www.xtuple.org/xtincident/view/bugs/18731)
-  _Address placeholders are not translated_
-- Fixed
-  issue #[18732](http://www.xtuple.org/xtincident/view/bugs/18732)
-  _All postgres users are showing up in user list_
-- Fixed
-  issue #[18769](http://www.xtuple.org/xtincident/view/bugs/18769)
-  _Cookies are not being deleted in any test-cases_
-- Completed
-  issue #[18770](http://www.xtuple.org/xtincident/view/bugs/18770)
-  _Integrate node-router into node-datasource_
-- Fixed
-  issue #[19017](http://www.xtuple.org/xtincident/view/bugs/19017)
-  _*Unable to select the project on selecting to create a new incident in dogfood_
-- Fixed
-  issue #[19199](http://www.xtuple.org/xtincident/view/bugs/19199)
-  _Security on reset password._
-- Implemented
-  issue #[20689](http://www.xtuple.org/xtincident/view/bugs/20689)
-  _Support for Barcode_
-- Implemented
-  issue #[20962](http://www.xtuple.org/xtincident/view/bugs/20962)
-  _Add support to enter Receipt transactions_
-- Implemented
-  issue #[21038](http://www.xtuple.org/xtincident/view/bugs/21038)
-  _Complete Issue to Shipping_
-- Fixed
-  issue #[21476](http://www.xtuple.org/xtincident/view/bugs/21476)
-  _*Unable to select back 'External' option as the Gateway for Credit cards in System Configuration screen_
-- Implemented
-  issue #[21508](http://www.xtuple.org/xtincident/view/bugs/21508)
-  _Add support for basic Work Order transactions_
-- Implemented
-  issue #[21584](http://www.xtuple.org/xtincident/view/bugs/21584)
-  _Organize pentaho properties in config.js_
-- Fixed
-  issue #[21686](http://www.xtuple.org/xtincident/view/bugs/21686)
-  _*Toolbar overlaps the Export icon making it unable to select in mobile devices_
-- Fixed
-  issue #[21889](http://www.xtuple.org/xtincident/view/bugs/21889)
-  _Mobile Web Client List View Items Overlap_
-- Fixed
-  issue #[21909](http://www.xtuple.org/xtincident/view/bugs/21909)
-  _ErpBI configuration not production ready_
-- Fixed
-  issue #[21978](http://www.xtuple.org/xtincident/view/bugs/21978)
-  _Item auto-populates on Sales Order when it should not_
-- Implemented
-  issue #[22059](http://www.xtuple.org/xtincident/view/bugs/22059)
-  _Implement Approve for Billing(select for billing)/Create Invoice at time of Shipping_
-- Implemented
-  issue #[22067](http://www.xtuple.org/xtincident/view/bugs/22067)
-  _Implement returns(credit memo)_
-- Implemented
-  issue #[22072](http://www.xtuple.org/xtincident/view/bugs/22072)
-  _Add support for Transfer Order_
-- Implemented
-  issue #[22129](http://www.xtuple.org/xtincident/view/bugs/22129)
-  _Support system printers for reports_
-- Fixed
-  issue #[22151](http://www.xtuple.org/xtincident/view/bugs/22151)
-  _Selecting ITEM-GROUP produces internal server error_
-- Fixed
-  issue #[22152](http://www.xtuple.org/xtincident/view/bugs/22152)
-  _Site is required in PostBooks_
-- Fixed
-  issue #[22172](http://www.xtuple.org/xtincident/view/bugs/22172)
-  _Item Group does not appear in Postbooks_
-- Implemented
-  issue #[22175](http://www.xtuple.org/xtincident/view/bugs/22175)
-  _Add the ability to issue to shipping and ship from Sales Order_
-- Fixed
-  issue #[22214](http://www.xtuple.org/xtincident/view/bugs/22214)
-  _Inventory gear options not showing on small devices_
-- Fixed
-  issue #[22224](http://www.xtuple.org/xtincident/view/bugs/22224)
-  _*Selecting 'Issue to Shipping' displays a JS console error and does not displays any response_
-- No Change Required
-  issue #[22227](http://www.xtuple.org/xtincident/view/bugs/22227)
-  _*Selecting to open an existing shipment hangs the application_
-- Fixed
-  issue #[22298](http://www.xtuple.org/xtincident/view/bugs/22298)
-  _*Selecting to add an address to a record displays an irrelevant dialog_
-- Implemented
-  issue #[22313](http://www.xtuple.org/xtincident/view/bugs/22313)
-  _Improve dev BI script_
-- Fixed
-  issue #[22368](http://www.xtuple.org/xtincident/view/bugs/22368)
-  _*Date format is displayed incorrectly in Transfer order list and Issue to shipping screens_
-- Fixed
-  issue #[22407](http://www.xtuple.org/xtincident/view/bugs/22407)
-  _*Selecting 'Issue to Shipping' without saving the Sales order and then selecting 'Save', doesn't populate the Sales order number_
-- Fixed
-  issue #[22408](http://www.xtuple.org/xtincident/view/bugs/22408)
-  _*Selecting Express Checkout without saving the Sales order and then selecting 'No' in the confirmation dialog displays a console_
-
-1.5.2 (2014/01/13)
-===============
-
-Features and bugfixes
----------------------
-
-- Fixed
-  issue #[22394](http://www.xtuple.org/xtincident/view/bugs/22394)
-  _Context queries can have punishingly slow performance_
-
-1.5.1 (2013/12/04)
-===============
-
-Critical deployment changes
----------------------------
-* File moved xtuple/test/shared/login_data.js -> xtuple/test/lib/login_data.js
-  `mv test/shared/login_data.js test/lib`
-* File moved xtuple/test/mocha/lib/demo-test.backup -> xtuple/test/lib/demo-test.backup
-  `mv test/mocha/lib/demo-test.backup test/lib`
-* If you have inventory registered you will have to change its location
-  `update xt.ext set ext_location = '/private-extensions' where ext_name = 'inventory'`
-
-Features and bugfixes
----------------------
-
-- Implemented
-  issue #[21224](http://www.xtuple.org/xtincident/view/bugs/21224)
-  _REST - Add support for a query "operator" to the REST API and Discovery Docs_
-- Implemented
-  issue #[21587](http://www.xtuple.org/xtincident/view/bugs/21587)
-  _Add Billing configuration_
-- Implemented
-  issue #[21625](http://www.xtuple.org/xtincident/view/bugs/21625)
-  _Implement Reason Code_
-- Fixed
-  issue #[21757](http://www.xtuple.org/xtincident/view/bugs/21757)
-  _Add Project Type to Project_
-- Fixed
-  issue #[21866](http://www.xtuple.org/xtincident/view/bugs/21866)
-  _Cost in Time Sheet (Worksheet) is null when entered through mobile_
-- Fixed
-  issue #[21979](http://www.xtuple.org/xtincident/view/bugs/21979)
-  _Arrowing up down through grid entry to not commit edited value to the model_
-- Implemented
-  issue #[21982](http://www.xtuple.org/xtincident/view/bugs/21982)
-  _Print invoices_
-- Implemented
-  issue #[21986](http://www.xtuple.org/xtincident/view/bugs/21986)
-  _Add support for Workflow to Sales Orders_
-- Implemented
-  issue #[21989](http://www.xtuple.org/xtincident/view/bugs/21989)
-  _Add support on item relation widget to search barcode and alias_
-- Implemented
-  issue #[21992](http://www.xtuple.org/xtincident/view/bugs/21992)
-  _Move inventory to the private-extensions repository_
-- Fixed
-  issue #[22031](http://www.xtuple.org/xtincident/view/bugs/22031)
-  _Can not change settings_
-- Completed
-  issue #[22049](http://www.xtuple.org/xtincident/view/bugs/22049)
-  _Cleanup the test folder_
-- Fixed
-  issue #[22063](http://www.xtuple.org/xtincident/view/bugs/22063)
-  _*Selecting to assign a privilege to a user account role displays 'Internal Server Error' dialog_
-- Fixed
-  issue #[22093](http://www.xtuple.org/xtincident/view/bugs/22093)
-  _View Characteristics disabled still allows Characteristics to be viewed_
-- Fixed
-  issue #[22094](http://www.xtuple.org/xtincident/view/bugs/22094)
-  _Characteristic Privilege declared by the CRM extension error_
-- Fixed
-  issue #[22098](http://www.xtuple.org/xtincident/view/bugs/22098)
-  _Disabled ViewClassCodes priv still allows user to view Class Code_
-- Fixed
-  issue #[22100](http://www.xtuple.org/xtincident/view/bugs/22100)
-  _Disable ViewCostCategory Priv still allows user to view Cost Category_
-- Fixed
-  issue #[22101](http://www.xtuple.org/xtincident/view/bugs/22101)
-  _Cost Category Privs not declared by extensions_
-- Fixed
-  issue #[22102](http://www.xtuple.org/xtincident/view/bugs/22102)
-  _MaintainClassCodes priv not declared by the project extension_
-- Fixed
-  issue #[22103](http://www.xtuple.org/xtincident/view/bugs/22103)
-  _Billing extension will not load without Sales_
-- Fixed
-  issue #[22104](http://www.xtuple.org/xtincident/view/bugs/22104)
-  _Incident Plus will not load without Project_
-- Fixed
-  issue #[22138](http://www.xtuple.org/xtincident/view/bugs/22138)
-  _Save on incident fails_
-- Fixed
-  issue #[22143](http://www.xtuple.org/xtincident/view/bugs/22143)
-  _Agent is required for New User Account_
-- Fixed
-  issue #[22166](http://www.xtuple.org/xtincident/view/bugs/22166)
-  _incident list color is all white_
-
-1.5.0 (2013/11/19)
-==================
-
-Features and bugfixes
----------------------
-
-- Implemented
-  issue #[18917](http://www.xtuple.org/xtincident/view/bugs/18917)
-  _Complete translation functionality_
-- Fixed
-  issue #[19681](http://www.xtuple.org/xtincident/view/bugs/19681)
-  _*Omnibus :It is not possible to re-attach a newly created and detached To Do item from a record_
-- Implemented
-  issue #[20438](http://www.xtuple.org/xtincident/view/bugs/20438)
-  _convert a quote to a sales order_
-- Fixed
-  issue #[20625](http://www.xtuple.org/xtincident/view/bugs/20625)
-  _Customer hold privileges are not enforced on Sales Order_
-- Implemented
-  issue #[20946](http://www.xtuple.org/xtincident/view/bugs/20946)
-  _implement rjson for basic compression_
-- Implemented
-  issue #[21038](http://www.xtuple.org/xtincident/view/bugs/21038)
-  _Complete Issue to Shipping_
-- Implemented
-  issue #[21100](http://www.xtuple.org/xtincident/view/bugs/21100)
-  _Sales Order Line Items should have a border to show_
-- Fixed
-  issue #[21166](http://www.xtuple.org/xtincident/view/bugs/21166)
-  _*Selecting to create a New To Do from the To Do tab of an incident generates a JS console error_
-- Fixed
-  issue #[21178](http://www.xtuple.org/xtincident/view/bugs/21178)
-  _*It is possible to delete the tasks to which Actual Time/Expenses are posted already_
-- Fixed
-  issue #[21245](http://www.xtuple.org/xtincident/view/bugs/21245)
-  _*Inactive Sales representatives are available for selection_
-- Fixed
-  issue #[21442](http://www.xtuple.org/xtincident/view/bugs/21442)
-  _Site Defaults in Mobile Web are not honoring user defaults_
-- Fixed
-  issue #[21448](http://www.xtuple.org/xtincident/view/bugs/21448)
-  _Error checking on functions is spotty in Mobile_
-- Fixed
-  issue #[21483](http://www.xtuple.org/xtincident/view/bugs/21483)
-  _*Omnibus: Records lists doesn't honor the selected 'Sort By' options_
-- Fixed
-  issue #[21491](http://www.xtuple.org/xtincident/view/bugs/21491)
-  _*Selecting to save a new To do item with an incident/Opportunity attached to it displays JS console error_
-- Fixed
-  issue #[21494](http://www.xtuple.org/xtincident/view/bugs/21494)
-  _The Alter Transaction Dates Privilege is not enforced on Issue to Shipping and Ship_
-- Fixed
-  issue #[21529](http://www.xtuple.org/xtincident/view/bugs/21529)
-  _Item Site is incomplete_
-- Implemented
-  issue #[21585](http://www.xtuple.org/xtincident/view/bugs/21585)
-  _Add support for Sales Categories_
-- Implemented
-  issue #[21587](http://www.xtuple.org/xtincident/view/bugs/21587)
-  _Add Billing configuration_
-- Implemented
-  issue #[21601](http://www.xtuple.org/xtincident/view/bugs/21601)
-  _Add mult-select support to worksheets_
-- Fixed
-  issue #[21604](http://www.xtuple.org/xtincident/view/bugs/21604)
-  _Terms implementation is incomplete_
-- Implemented
-  issue #[21614](http://www.xtuple.org/xtincident/view/bugs/21614)
-  _Implement Bank Account_
-- Fixed
-  issue #[21617](http://www.xtuple.org/xtincident/view/bugs/21617)
-  _*Unable to scroll the Time Sheets List in a new Worksheet_
-- Implemented
-  issue #[21625](http://www.xtuple.org/xtincident/view/bugs/21625)
-  _Implement Reason Code_
-- Fixed
-  issue #[21633](http://www.xtuple.org/xtincident/view/bugs/21633)
-  _*Unable to delete a Sales order_
-- Fixed
-  issue #[21650](http://www.xtuple.org/xtincident/view/bugs/21650)
-  _*'Ship' button is active in the Issue to Shipping screen when 'Ship Orders' privilege is disabled for the user_
-- Fixed
-  issue #[21657](http://www.xtuple.org/xtincident/view/bugs/21657)
-  _Grid row doesn't refresh_
-- Fixed
-  issue #[21659](http://www.xtuple.org/xtincident/view/bugs/21659)
-  _Mobile Timecard entry... remembering fields so don't need to continually enter same data_
-- Fixed
-  issue #[21666](http://www.xtuple.org/xtincident/view/bugs/21666)
-  _*Unable to delete a Prospect_
-- Fixed
-  issue #[21667](http://www.xtuple.org/xtincident/view/bugs/21667)
-  _*Unable to delete a Customer_
-- Fixed
-  issue #[21670](http://www.xtuple.org/xtincident/view/bugs/21670)
-  _*Selecting to discard the changes of a Worksheet hangs the application_
-- Implemented
-  issue #[21679](http://www.xtuple.org/xtincident/view/bugs/21679)
-  _Tweak MW refresh icon_
-- Fixed
-  issue #[21680](http://www.xtuple.org/xtincident/view/bugs/21680)
-  _Timesheets in Mobile Web Client Default to Billable, when Customer is Selected_
-- Implemented
-  issue #[21684](http://www.xtuple.org/xtincident/view/bugs/21684)
-  _Implement Invoices_
-- Fixed
-  issue #[21704](http://www.xtuple.org/xtincident/view/bugs/21704)
-  _Unable to use Sales Analysis due to Blocked page_
-- Implemented
-  issue #[21739](http://www.xtuple.org/xtincident/view/bugs/21739)
-  _Projects should support characteristics_
-- Implemented
-  issue #[21750](http://www.xtuple.org/xtincident/view/bugs/21750)
-  _Develop OLAP client support for dashboards_
-- Implemented
-  issue #[21762](http://www.xtuple.org/xtincident/view/bugs/21762)
-  _Add support for grid entry to project_
-- Fixed
-  issue #[21801](http://www.xtuple.org/xtincident/view/bugs/21801)
-  _xt error on desktop 4.1  with Mobile client_
-- Implemented
-  issue #[21807](http://www.xtuple.org/xtincident/view/bugs/21807)
-  _Develop install script for Pentaho_
-- Implemented
-  issue #[21821](http://www.xtuple.org/xtincident/view/bugs/21821)
-  _Need new welcome screen metric for MW_
-- Fixed
-  issue #[21831](http://www.xtuple.org/xtincident/view/bugs/21831)
-  _Can not run xt-mobile scripts on db upgraded from 4.1.0 to 4.2.0_
-- Implemented
-  issue #[21834](http://www.xtuple.org/xtincident/view/bugs/21834)
-  _Prerequisite Checks for Mobile Required_
-- Fixed
-  issue #[21851](http://www.xtuple.org/xtincident/view/bugs/21851)
-  _mobile no longer uses bindAddress_
-- Implemented
-  issue #[21864](http://www.xtuple.org/xtincident/view/bugs/21864)
-  _assign project tasks to resources_
-- Fixed
-  issue #[21894](http://www.xtuple.org/xtincident/view/bugs/21894)
-  _Address can not be updated_
-- Implemented
-  issue #[21895](http://www.xtuple.org/xtincident/view/bugs/21895)
-  _Initial analytic charts for dashboard in Sales BI Extension_
-- Fixed
-  issue #[21933](http://www.xtuple.org/xtincident/view/bugs/21933)
-  _Client not responding after log in_
-- Fixed
-  issue #[21994](http://www.xtuple.org/xtincident/view/bugs/21994)
-  _*Selecting to run the install script displays Syntax error_
-
-This version requires version 4.2.0 or higher of xTuple PostBooks or commercial edition database.
-
-1.4.6 (2013/11/xx)
-==================
-Critical deployment changes
----------------------------
-- The Sales Dashboard has been redesigned to show sales data from analytic cubes.  To connect to the BI Server
-you must define:
-
-   biServer: {
-        hostname: "localhost",
-        port: 8080,
-        catalog: "xTuple",
-        tenantname: "default",
-        keyFile: "./lib/rest-keys/server.key"
-      }
-in config.js.  Also, the Sales Dashboard is now structured in a private extension:
-
-   https://github.com/xtuple/private-extensions/tree/master/source/bi
-
-1.4.5 (2013/10/11)
-==================
-
-Features and bugfixes
----------------------
-
-- Fixed
-  issue #[19869](http://www.xtuple.org/xtincident/view/bugs/19869)
-  _*Omnibus: Locked record is displayed on selecting to open a contact after discarding new contact screen opened from it _
-- Fixed
-  issue #[19957](http://www.xtuple.org/xtincident/view/bugs/19957)
-  _Selecting to create a new Customer/Prospect from the customer field of Quote screen doesn't populates the customer automatically_
-- Fixed
-  issue #[20000](http://www.xtuple.org/xtincident/view/bugs/20000)
-  _* It is not possible to delete the customer SHIP-TO on reopening the customer_
-- Fixed
-  issue #[20012](http://www.xtuple.org/xtincident/view/bugs/20012)
-  _*Selected sales representative commission rate is not displayed automatically on the Customer screen_
-- Fixed
-  issue #[20064](http://www.xtuple.org/xtincident/view/bugs/20064)
-  _*Ship-To Number search screen is not labeled_
-- Fixed
-  issue #[20071](http://www.xtuple.org/xtincident/view/bugs/20071)
-  _Saving while Customer Ship-To is open gives error then causes other issues_
-- Fixed
-  issue #[20173](http://www.xtuple.org/xtincident/view/bugs/20173)
-  _*It is not possible to assign a Tax Authority to a Tax Code_
-- Fixed
-  issue #[20196](http://www.xtuple.org/xtincident/view/bugs/20196)
-  _*Data Source error is displayed on selecting to search the item sites screen with 'Class Code' filter_
-- Duplicate
-  issue #[20198](http://www.xtuple.org/xtincident/view/bugs/20198)
-  _*'Mask' and 'Validator' fields present under characteristic of type 'Text' are not functional_
-- Implemented
-  issue #[20311](http://www.xtuple.org/xtincident/view/bugs/20311)
-  _Welcome screen iframe does not scroll on iOS devices. CSS fix attached. ASM#5469_
-- Reopened
-  issue #[20332](http://www.xtuple.org/xtincident/view/bugs/20332)
-  _Error Adding a Sales Order to an Opportunity_
-- Implemented
-  issue #[20682](http://www.xtuple.org/xtincident/view/bugs/20682)
-  _Inventory History Report_
-- No Change Required
-  issue #[20885](http://www.xtuple.org/xtincident/view/bugs/20885)
-  _Time Expense Version has Incorrect title_
-- Fixed
-  issue #[20888](http://www.xtuple.org/xtincident/view/bugs/20888)
-  _Class Code List updates after a Discard_
-- Fixed
-  issue #[20981](http://www.xtuple.org/xtincident/view/bugs/20981)
-  _BI Readme steps updated_
-- Fixed
-  issue #[20994](http://www.xtuple.org/xtincident/view/bugs/20994)
-  _Clicking on Advanced Search displays History_
-- Fixed
-  issue #[21008](http://www.xtuple.org/xtincident/view/bugs/21008)
-  _*CRM Dashboard charts are duplicated on selecting to refresh_
-- Fixed
-  issue #[21062](http://www.xtuple.org/xtincident/view/bugs/21062)
-  _Using Help Pullout Tab gives Java Console Error_
-- Fixed
-  issue #[21110](http://www.xtuple.org/xtincident/view/bugs/21110)
-  _*Omnibus: Record is locked for some time on selecting 'Save and New' or 'New' button from the record screen_
-- Fixed
-  issue #[21114](http://www.xtuple.org/xtincident/view/bugs/21114)
-  _*observation: Unable to delete a Sales Representative_
-- Fixed
-  issue #[21181](http://www.xtuple.org/xtincident/view/bugs/21181)
-  _*New Quotes/Sales Orders created from the Opportunity screen are not displayed as attached to the Opportunity_
-- Fixed
-  issue #[21182](http://www.xtuple.org/xtincident/view/bugs/21182)
-  _*Omnibus: Selecting to delete a characteristic and save the record displays irrelevant dialog_
-- Fixed
-  issue #[21230](http://www.xtuple.org/xtincident/view/bugs/21230)
-  _*Employee screen doesn't save the Group attached to it_
-- Fixed
-  issue #[21232](http://www.xtuple.org/xtincident/view/bugs/21232)
-  _*Translation is required for the description label in the 'Advanced Search' panel of Employee Group list_
-- Duplicate
-  issue #[21248](http://www.xtuple.org/xtincident/view/bugs/21248)
-  _* Translation is required for the timeExpense label in About screen_
-- Fixed
-  issue #[21270](http://www.xtuple.org/xtincident/view/bugs/21270)
-  _*Translation is required for the  label in About screen_
-- Fixed
-  issue #[21383](http://www.xtuple.org/xtincident/view/bugs/21383)
-  _Found/Fixed in lists are not populated on Advanced Search_
-- Fixed
-  issue #[21396](http://www.xtuple.org/xtincident/view/bugs/21396)
-  _Misbehavior in Time/Expense editor panels_
-- Fixed
-  issue #[21401](http://www.xtuple.org/xtincident/view/bugs/21401)
-  _Gear on worksheet list inconsistent_
-- Fixed
-  issue #[21402](http://www.xtuple.org/xtincident/view/bugs/21402)
-  _All new records prompt to discard on iPad_
-- No Change Required
-  issue #[21415](http://www.xtuple.org/xtincident/view/bugs/21415)
-  _Attaching an Incident or Contact to an Account will not save_
-- Fixed
-  issue #[21419](http://www.xtuple.org/xtincident/view/bugs/21419)
-  _Worksheet owned by person who created it_
-- Fixed
-  issue #[21425](http://www.xtuple.org/xtincident/view/bugs/21425)
-  _List box editor doesn't validate_
-- Fixed
-  issue #[21437](http://www.xtuple.org/xtincident/view/bugs/21437)
-  _Pickers not populating on configuration_
-- Fixed
-  issue #[21440](http://www.xtuple.org/xtincident/view/bugs/21440)
-  _*Delete option is inactive for Tax Authorities_
-- Fixed
-  issue #[21451](http://www.xtuple.org/xtincident/view/bugs/21451)
-  _Timesheet remembers my location every time_
-- Fixed
-  issue #[21454](http://www.xtuple.org/xtincident/view/bugs/21454)
-  _Search box pushed off the screen_
-- Fixed
-  issue #[21473](http://www.xtuple.org/xtincident/view/bugs/21473)
-  _Unable to login Standard if Inventory or Sales is not enabled_
-- Fixed
-  issue #[21479](http://www.xtuple.org/xtincident/view/bugs/21479)
-  _*'View Inventory History' privilege under 'Inventory' module requires translation_
-- Fixed
-  issue #[21480](http://www.xtuple.org/xtincident/view/bugs/21480)
-  _*Transaction Date, Transaction Type and Order Type options in the Sort By list of 'Inventory History' require translation_
-- Implemented
-  issue #[21487](http://www.xtuple.org/xtincident/view/bugs/21487)
-  _grid entry in quote_
-- Fixed
-  issue #[21496](http://www.xtuple.org/xtincident/view/bugs/21496)
-  _*It is possible to select a project in 'Complete' status to create a time/expense sheet_
-- Fixed
-  issue #[21500](http://www.xtuple.org/xtincident/view/bugs/21500)
-  _Icons on pickers overlap text when scrolling_
-- Fixed
-  issue #[21505](http://www.xtuple.org/xtincident/view/bugs/21505)
-  _Mobile object names inconsistent with precedent_
-- Fixed
-  issue #[21515](http://www.xtuple.org/xtincident/view/bugs/21515)
-  _*Incorrect Project Task is displayed in the Time/Expense sheet of a worksheet_
-- Fixed
-  issue #[21540](http://www.xtuple.org/xtincident/view/bugs/21540)
-  _Characteristics don't get disabled_
-- Fixed
-  issue #[21541](http://www.xtuple.org/xtincident/view/bugs/21541)
-  _*Unable to update the Schedule date of a Quote_
-- Fixed
-  issue #[21565](http://www.xtuple.org/xtincident/view/bugs/21565)
-  _Selecting new time entry brings up prior entry_
-- Implemented
-  issue #[21581](http://www.xtuple.org/xtincident/view/bugs/21581)
-  _Add freight class picker to item workspace_
-- Fixed
-  issue #[21605](http://www.xtuple.org/xtincident/view/bugs/21605)
-  _Document linkages are only showing up on one side_
-- Fixed
-  issue #[21627](http://www.xtuple.org/xtincident/view/bugs/21627)
-  _Sales analysis (and other) object name problem_
-
-
-1.4.4 (2013/09/27)
-==================
-
-Features and bugfixes
----------------------
-
-- Implemented
-  issue #[18833](http://www.xtuple.org/xtincident/view/bugs/18833)
-  _Would like user customizable content on lists_
-- Implemented
-  issue #[19647](http://www.xtuple.org/xtincident/view/bugs/19647)
-  _Report dates and currency must be localizable_
-- Fixed
-  issue #[19858](http://www.xtuple.org/xtincident/view/bugs/19858)
-  _*Unable to delete a Project Task from Project Tasks screen_
-- Fixed
-  issue #[20449](http://www.xtuple.org/xtincident/view/bugs/20449)
-  _Incidents gives error when CRM is only extension_
-- Implemented
-  issue #[20677](http://www.xtuple.org/xtincident/view/bugs/20677)
-  _Create Location object_
-- Implemented
-  issue #[20683](http://www.xtuple.org/xtincident/view/bugs/20683)
-  _Backlog Report_
-- Implemented
-  issue #[20684](http://www.xtuple.org/xtincident/view/bugs/20684)
-  _Create Shipments List object and views with return action_
-- Implemented
-  issue #[20734](http://www.xtuple.org/xtincident/view/bugs/20734)
-  _Issue to Shipping_
-- Fixed
-  issue #[20800](http://www.xtuple.org/xtincident/view/bugs/20800)
-  _*Delete option is active for contacts attached to ToDoitem/Opportunity_
-- Fixed
-  issue #[20927](http://www.xtuple.org/xtincident/view/bugs/20927)
-  _Install script says finished when it is not_
-- Fixed
-  issue #[20954](http://www.xtuple.org/xtincident/view/bugs/20954)
-  _Problems in report data from data-from-key_
-- Fixed
-  issue #[21093](http://www.xtuple.org/xtincident/view/bugs/21093)
-  _*No error message is displayed on selecting to delete an item with item site created for it_
-- Fixed
-  issue #[21176](http://www.xtuple.org/xtincident/view/bugs/21176)
-  _*Unable to save comments for a To do item_
-- Fixed
-  issue #[21189](http://www.xtuple.org/xtincident/view/bugs/21189)
-  _Files over 1MB does not appear to complete upload_
-- Implemented
-  issue #[21251](http://www.xtuple.org/xtincident/view/bugs/21251)
-  _Add credit card processing support to Sales Order_
-- Fixed
-  issue #[21277](http://www.xtuple.org/xtincident/view/bugs/21277)
-  _T/E mobile not enforcing view other rules._
-- Fixed
-  issue #[21306](http://www.xtuple.org/xtincident/view/bugs/21306)
-  _Menu presentation order unpredictable_
-- Fixed
-  issue #[21316](http://www.xtuple.org/xtincident/view/bugs/21316)
-  _Time and Expense uneditable when unapproved_
-- Completed
-  issue #[21327](http://www.xtuple.org/xtincident/view/bugs/21327)
-  _Sales cubes dimension and measure terminology_
-- Completed
-  issue #[21360](http://www.xtuple.org/xtincident/view/bugs/21360)
-  _add monthly calendar to sales cubes_
-- Completed
-  issue #[21361](http://www.xtuple.org/xtincident/view/bugs/21361)
-  _Should be able to save Sales Analysis query_
-- Fixed
-  issue #[21368](http://www.xtuple.org/xtincident/view/bugs/21368)
-  _Worksheets bring in wrong customer reference_
-- Fixed
-  issue #[21385](http://www.xtuple.org/xtincident/view/bugs/21385)
-  _TE Worksheet List does not filter on on Date_
-- Fixed
-  issue #[21399](http://www.xtuple.org/xtincident/view/bugs/21399)
-  _Can't find worksheet total hours_
-- Fixed
-  issue #[21403](http://www.xtuple.org/xtincident/view/bugs/21403)
-  _Worksheets should default to self as the Employee_
-- Fixed
-  issue #[21407](http://www.xtuple.org/xtincident/view/bugs/21407)
-  _Field missing on Worksheet:  hourly cost_
-- Fixed
-  issue #[21427](http://www.xtuple.org/xtincident/view/bugs/21427)
-  _Inventory Extension adding expense category to setup menu_
-- Fixed
-  issue #[21432](http://www.xtuple.org/xtincident/view/bugs/21432)
-  _forgot password error_
-- Fixed
-  issue #[21439](http://www.xtuple.org/xtincident/view/bugs/21439)
-  _Picker is too wide on money widgets_
-- Fixed
-  issue #[21442](http://www.xtuple.org/xtincident/view/bugs/21442)
-  _Site Defaults in Mobile Web are not honoring user defaults_
-- Fixed
-  issue #[21453](http://www.xtuple.org/xtincident/view/bugs/21453)
-  _Firefox is blocking mobile help content_
-- Fixed
-  issue #[21455](http://www.xtuple.org/xtincident/view/bugs/21455)
-  _Sort is not working for Sort and Layout Attribute Pickers_
-- Fixed
-  issue #[21478](http://www.xtuple.org/xtincident/view/bugs/21478)
-  _*Selecting to create new Shipment record displays insufficient privileges dialog_
-- Fixed
-  issue #[21482](http://www.xtuple.org/xtincident/view/bugs/21482)
-  _*Omnibus: Blank screen is displayed on selecting to print any record/records list_
-- Fixed
-  issue #[21495](http://www.xtuple.org/xtincident/view/bugs/21495)
-  _Cannot Search for Incident Contact_
-- Fixed
-  issue #[21497](http://www.xtuple.org/xtincident/view/bugs/21497)
-  _Time Expense has dependency on Sales_
-- Fixed
-  issue #[21498](http://www.xtuple.org/xtincident/view/bugs/21498)
-  _Users can not save time sheet if no prvilege_
-- Fixed
-  issue #[21524](http://www.xtuple.org/xtincident/view/bugs/21524)
-  _Printing Admin Account causes unhandled Error_
-- Fixed
-  issue #[21532](http://www.xtuple.org/xtincident/view/bugs/21532)
-  _Cannot open an existing Item_
-
-
-1.4.3 (2013/09/11)
-==================
-
-Features and bugfixes
----------------------
-- Implemented
-  issue #[18488](http://www.xtuple.org/xtincident/view/bugs/18488)
-  _Add sort option to Mobile client_
-- Fixed
-  issue #[19395](http://www.xtuple.org/xtincident/view/bugs/19395)
-  _*Unable to delete a contact with no address_
-- Fixed
-  issue #[19680](http://www.xtuple.org/xtincident/view/bugs/19680)
-  _Email profiles are not editable_
-- Fixed
-  issue #[19966](http://www.xtuple.org/xtincident/view/bugs/19966)
-  _*It is possible to create a Quote without any line item_
-- Fixed
-  issue #[19992](http://www.xtuple.org/xtincident/view/bugs/19992)
-  _*New quote created from a Customer does not populates the customer number  automatically in 'Customer' field of quote screen_
-- Fixed
-  issue #[19993](http://www.xtuple.org/xtincident/view/bugs/19993)
-  _*Detach button in the Quotes panel of a customer is not functional_
-- Implemented
-  issue #[20445](http://www.xtuple.org/xtincident/view/bugs/20445)
-  _Login Page should have "Forgot Password" link/functionality_
-- Fixed
-  issue #[20458](http://www.xtuple.org/xtincident/view/bugs/20458)
-  _Editing Worksheet Time Billable does not save_
-- Fixed
-  issue #[20460](http://www.xtuple.org/xtincident/view/bugs/20460)
-  _Posting a Worksheet does not appear to do anything_
-- Implemented
-  issue #[20782](http://www.xtuple.org/xtincident/view/bugs/20782)
-  _add vCard export functionality for contacts_
-- Implemented
-  issue #[20851](http://www.xtuple.org/xtincident/view/bugs/20851)
-  _REST support for field-level queries_
-- Fixed
-  issue #[20909](http://www.xtuple.org/xtincident/view/bugs/20909)
-  _ListRelationsEditorBox fails if you delete an intermediate item_
-- Fixed
-  issue #[20960](http://www.xtuple.org/xtincident/view/bugs/20960)
-  _Cannot create new Site_
-- Fixed
-  issue #[20961](http://www.xtuple.org/xtincident/view/bugs/20961)
-  _Deleting a Site does not work_
-- Completed
-  issue #[20987](http://www.xtuple.org/xtincident/view/bugs/20987)
-  _Pentaho tenant to include server IP_
-- Implemented
-  issue #[21046](http://www.xtuple.org/xtincident/view/bugs/21046)
-  _Add context messaging tools for Mobile Web UI (Sales Analysis)_
-- Fixed
-  issue #[21097](http://www.xtuple.org/xtincident/view/bugs/21097)
-  _*Selecting to edit and save an item site displays irrelevant message_
-- Fixed
-  issue #[21112](http://www.xtuple.org/xtincident/view/bugs/21112)
-  _*Omnibus: Action icon button doesn't respond on clicking when 'Advanced Search' panel is open for the list of records_
-- Fixed
-  issue #[21120](http://www.xtuple.org/xtincident/view/bugs/21120)
-  _*Observation: Selecting to save the Tax rate with currency set to default displays 'currency is required' message irrelevantly_
-- Fixed
-  issue #[21121](http://www.xtuple.org/xtincident/view/bugs/21121)
-  _*Selecting 'Save' in the Tax Rate screen without selecting the Tax Code doesn't displays any error message_
-- Fixed
-  issue #[21123](http://www.xtuple.org/xtincident/view/bugs/21123)
-  _Multi-Site option should not be allowed off if there are Multi-sites_
-- Fixed
-  issue #[21158](http://www.xtuple.org/xtincident/view/bugs/21158)
-  _*translation required for effective and expiry date warning messages_
-- Fixed
-  issue #[21201](http://www.xtuple.org/xtincident/view/bugs/21201)
-  _*Delete option is active for Used contacts_
-- Fixed
-  issue #[21234](http://www.xtuple.org/xtincident/view/bugs/21234)
-  _*It is possible to edit and save the Billing rate currency of the Time And Expense sheets of an Approved worksheet_
-- Fixed
-  issue #[21256](http://www.xtuple.org/xtincident/view/bugs/21256)
-  _Project does not save with filter_
-- Fixed
-  issue #[21276](http://www.xtuple.org/xtincident/view/bugs/21276)
-  _mobile TE scrolling_
-- Fixed
-  issue #[21289](http://www.xtuple.org/xtincident/view/bugs/21289)
-  _A user who only has personal privileges can not create records_
-- Fixed
-  issue #[21302](http://www.xtuple.org/xtincident/view/bugs/21302)
-  _Task assignments not working on worksheets_
-- Fixed
-  issue #[21359](http://www.xtuple.org/xtincident/view/bugs/21359)
-  _Worksheet list unacceptably slow_
-- Fixed
-  issue #[21374](http://www.xtuple.org/xtincident/view/bugs/21374)
-  _Last saved filter doesn't default_
-- Fixed
-  issue #[21375](http://www.xtuple.org/xtincident/view/bugs/21375)
-  _Default search criteria appearing on widget searches_
-- Fixed
-  issue #[21395](http://www.xtuple.org/xtincident/view/bugs/21395)
-  _Selecting worksheets sometimes opens wrong selection_
-
-
-1.4.2 (2013/08/23)
-==================
-
-Features and bugfixes
----------------------
-- Fixed
-  issue #[21260](http://www.xtuple.org/xtincident/view/bugs/21260)
-  _XT.filter table naming conflict with public.filter_
-
-
-1.4.1 (2013/08/21)
-===============
-
-Features and bugfixes
-----------------
-- Implemented
-  issue #[18668](http://www.xtuple.org/xtincident/view/bugs/18668)
-  _Initial documentation build for Mobile platform_
-- Implemented
-  issue #[19294](http://www.xtuple.org/xtincident/view/bugs/19294)
-  _OAuth 2.0 - Refactor route and functor mapping in Express to use a loop for loading_
-- Implemented
-  issue #[19303](http://www.xtuple.org/xtincident/view/bugs/19303)
-  _REST - Add Discovery Service routes_
-- Implemented
-  issue #[19305](http://www.xtuple.org/xtincident/view/bugs/19305)
-  _REST - Add route handler functions for end point CRUD_
-- Implemented
-  issue #[19306](http://www.xtuple.org/xtincident/view/bugs/19306)
-  _REST - Add "service" endpoints_
-- Completed
-  issue #[19443](http://www.xtuple.org/xtincident/view/bugs/19443)
-  _Use data schema in Pentaho report scripts_
-- Fixed
-  issue #[20195](http://www.xtuple.org/xtincident/view/bugs/20195)
-  _*Irrelevant behavior is observed on re-opening a quote_
-- Fixed
-  issue #[20265](http://www.xtuple.org/xtincident/view/bugs/20265)
-  _OAUTH - Existing session/cookie causes client to load. Fix redirect to auth dialog page_
-- Fixed
-  issue #[20458](http://www.xtuple.org/xtincident/view/bugs/20458)
-  _Editing Worksheet Time Billable does not save_
-- Fixed
-  issue #[20642](http://www.xtuple.org/xtincident/view/bugs/20642)
-  _Filters broken on incidents_
-- Implemented
-  issue #[20864](http://www.xtuple.org/xtincident/view/bugs/20864)
-  _Grid entry for Sales Order on Desktop based browser client_
-- Implemented
-  issue #[20866](http://www.xtuple.org/xtincident/view/bugs/20866)
-  _Allow filters to be saved on lists_
-- Fixed
-  issue #[20886](http://www.xtuple.org/xtincident/view/bugs/20886)
-  _Searchable is required on New Characteristic_
-- Implemented
-  issue #[20890](http://www.xtuple.org/xtincident/view/bugs/20890)
-  _OAuth2 - Admin Interface Usability Tweaks_
-- Fixed
-  issue #[20891](http://www.xtuple.org/xtincident/view/bugs/20891)
-  _Add "website" to contact overview_
-- Fixed
-  issue #[20898](http://www.xtuple.org/xtincident/view/bugs/20898)
-  _Item Site not populating correctly for Sales Order_
-- Fixed
-  issue #[20899](http://www.xtuple.org/xtincident/view/bugs/20899)
-  _Advanced Search does not display list after clearing bad data_
-- Fixed
-  issue #[20902](http://www.xtuple.org/xtincident/view/bugs/20902)
-  _Adding an Item to Quote_
-- Fixed
-  issue #[20908](http://www.xtuple.org/xtincident/view/bugs/20908)
-  _Dashboard Charts shrink upon returning to Dashboard screen_
-- Fixed
-  issue #[20932](http://www.xtuple.org/xtincident/view/bugs/20932)
-  _Dashboard Query is not working_
-- Fixed
-  issue #[20979](http://www.xtuple.org/xtincident/view/bugs/20979)
-  _oath2client table entry for Pentaho needs to use default database_
-- Fixed
-  issue #[20983](http://www.xtuple.org/xtincident/view/bugs/20983)
-  _History shows "undefined" for many objects_
-- Fixed
-  issue #[20989](http://www.xtuple.org/xtincident/view/bugs/20989)
-  _oauth2 check for JWT issued in the future causes timing problem_
-- Fixed
-  issue #[21016](http://www.xtuple.org/xtincident/view/bugs/21016)
-  _Cost Categories Desciption alignment is wrong_
-- Fixed
-  issue #[21051](http://www.xtuple.org/xtincident/view/bugs/21051)
-  _Characteristic - No Error message when trying to save without a role_
-- Fixed
-  issue #[21055](http://www.xtuple.org/xtincident/view/bugs/21055)
-  _Updating Extensions on Role will not allow application to load on login_
-- Fixed
-  issue #[21066](http://www.xtuple.org/xtincident/view/bugs/21066)
-  _Editing a Sales Order gives _shipped error_
-- Fixed
-  issue #[21129](http://www.xtuple.org/xtincident/view/bugs/21129)
-  _Sales Analysis user can not use Pentaho single sign on without admin privilege_
-- Fixed
-  issue #[21138](http://www.xtuple.org/xtincident/view/bugs/21138)
-  _Relation Lists are not loading Properly in Workspaces_
-
-
-1.4.0 (2013/08/07)
-===============
-
-Features and bugfixes
-----------------
-- Fixed
-  issue #[18711](http://www.xtuple.org/xtincident/view/bugs/18711)
-  _Edit Owner privilege is not enforced_
-- Fixed
-  issue #[18724](http://www.xtuple.org/xtincident/view/bugs/18724)
-  _ReassignToDoItems privilege is not enforced_
-- Fixed
-  issue #[18726](http://www.xtuple.org/xtincident/view/bugs/18726)
-  _*Left of Contact Address Not Visible in panel_
-- Fixed
-  issue #[18968](http://www.xtuple.org/xtincident/view/bugs/18968)
-  _Panel sizing on Item workspace_
-- Fixed
-  issue #[19042](http://www.xtuple.org/xtincident/view/bugs/19042)
-  _Omnibus: Observation: New User Account created from Owner field is not populated automatically in Owner field_
-- Implemented
-  issue #[19626](http://www.xtuple.org/xtincident/view/bugs/19626)
-  _Add link to google maps_
-- Completed
-  issue #[19645](http://www.xtuple.org/xtincident/view/bugs/19645)
-  _Install/build process for reports_
-- Fixed
-  issue #[19711](http://www.xtuple.org/xtincident/view/bugs/19711)
-  _*Irrelevant behavior is observed on selecting to save the role assigned to the CRM Account_
-- Fixed
-  issue #[19796](http://www.xtuple.org/xtincident/view/bugs/19796)
-  _Quote shows costs when users do not have cost privilege_
-- Fixed
-  issue #[19800](http://www.xtuple.org/xtincident/view/bugs/19800)
-  _Site should only appear on quote when multi-site enabled_
-- Implemented
-  issue #[19801](http://www.xtuple.org/xtincident/view/bugs/19801)
-  _Site should default on quote_
-- Fixed
-  issue #[19805](http://www.xtuple.org/xtincident/view/bugs/19805)
-  _User should not be able to edit quote price unless they have privileges to do so_
-- Fixed
-  issue #[19859](http://www.xtuple.org/xtincident/view/bugs/19859)
-  _*Selecting to create a new project task from an existing project task displays Data source error_
-- Fixed
-  issue #[19967](http://www.xtuple.org/xtincident/view/bugs/19967)
-  _*Irrelevant dialog is displayed on saving a quote_
-- Fixed
-  issue #[20008](http://www.xtuple.org/xtincident/view/bugs/20008)
-  _Converting prospect to customer freezes client_
-- Fixed
-  issue #[20068](http://www.xtuple.org/xtincident/view/bugs/20068)
-  _Click Apply on Customer Groups will Lock the record_
-- Implemented
-  issue #[20190](http://www.xtuple.org/xtincident/view/bugs/20190)
-  _Mobile Client Phone Numbers Should be Clickable_
-- Implemented
-  issue #[20380](http://www.xtuple.org/xtincident/view/bugs/20380)
-  _Sales analysis view_
-- Fixed
-  issue #[20489](http://www.xtuple.org/xtincident/view/bugs/20489)
-  _Item does not display Wholesale Price_
-- Implemented
-  issue #[20524](http://www.xtuple.org/xtincident/view/bugs/20524)
-  _build_database script_
-- Fixed
-  issue #[20555](http://www.xtuple.org/xtincident/view/bugs/20555)
-  _new authentication does not work with pgbouncer_
-- Implemented
-  issue #[20559](http://www.xtuple.org/xtincident/view/bugs/20559)
-  _Need to create an interface to manage Oauth_
-- Implemented
-  issue #[20574](http://www.xtuple.org/xtincident/view/bugs/20574)
-  _sales order should use item and site instead of itemsite_
-- No Change Required
-  issue #[20596](http://www.xtuple.org/xtincident/view/bugs/20596)
-  _Numbers cut off by scroller_
-- Implemented
-  issue #[20614](http://www.xtuple.org/xtincident/view/bugs/20614)
-  _Need an installer methodology for the mobile client and extensions_
-- Fixed
-  issue #[20638](http://www.xtuple.org/xtincident/view/bugs/20638)
-  _Attach option on relation boxes should not display objects already attached to other objects_
-- Fixed
-  issue #[20672](http://www.xtuple.org/xtincident/view/bugs/20672)
-  _Admin Role gives Java Console Error_
-- Fixed
-  issue #[20673](http://www.xtuple.org/xtincident/view/bugs/20673)
-  _User Account gives Disable Export error_
-- Implemented
-  issue #[20676](http://www.xtuple.org/xtincident/view/bugs/20676)
-  _Create Inventory Configuration Settings_
-- Implemented
-  issue #[20715](http://www.xtuple.org/xtincident/view/bugs/20715)
-  _Sales dashboard_
-- Implemented
-  issue #[20723](http://www.xtuple.org/xtincident/view/bugs/20723)
-  _Single signon support for Pentaho_
-- Implemented
-  issue #[20726](http://www.xtuple.org/xtincident/view/bugs/20726)
-  _Support for Pentaho dynamic OLAP cubes based on organization_
-- Fixed
-  issue #[20736](http://www.xtuple.org/xtincident/view/bugs/20736)
-  _xt package pkg tables missing triggers, causing issues loading packages_
-- Implemented
-  issue #[20746](http://www.xtuple.org/xtincident/view/bugs/20746)
-  _Multi-tenant support for Sales cubes_
-- Implemented
-  issue #[20747](http://www.xtuple.org/xtincident/view/bugs/20747)
-  _Multi-tenant support for sales ETL_
-- Fixed
-  issue #[20760](http://www.xtuple.org/xtincident/view/bugs/20760)
-  _*Quantity UOM is not available for selection in SO Line item screen_
-- Implemented
-  issue #[20771](http://www.xtuple.org/xtincident/view/bugs/20771)
-  _generate p12 in oauth generate-key route_
-- No Change Required
-  issue #[20774](http://www.xtuple.org/xtincident/view/bugs/20774)
-  _access user_account REST_
-- Fixed
-  issue #[20775](http://www.xtuple.org/xtincident/view/bugs/20775)
-  _Remove xtbatch schema if not being used by mobile_
-- Implemented
-  issue #[20780](http://www.xtuple.org/xtincident/view/bugs/20780)
-  _improve maven reports deployment_
-- Fixed
-  issue #[20785](http://www.xtuple.org/xtincident/view/bugs/20785)
-  _Change Password does not remove Confirmed Password_
-- Fixed
-  issue #[20792](http://www.xtuple.org/xtincident/view/bugs/20792)
-  _*Username of a User Account is editable_
-- Fixed
-  issue #[20803](http://www.xtuple.org/xtincident/view/bugs/20803)
-  _*Observation: Newly created records are displayed as locked on opening the records immediately after creation_
-- Fixed
-  issue #[20814](http://www.xtuple.org/xtincident/view/bugs/20814)
-  _Cannot save a Sales Order_
-- Implemented
-  issue #[20820](http://www.xtuple.org/xtincident/view/bugs/20820)
-  _REST - Expose all objects needed for basic relation functionality to work_
-- Fixed
-  issue #[20848](http://www.xtuple.org/xtincident/view/bugs/20848)
-  _Advanced Search Groupbox is too wide_
-- Implemented
-  issue #[20865](http://www.xtuple.org/xtincident/view/bugs/20865)
-  _Add dropdown indicator icon to picker_
-- Implemented
-  issue #[20868](http://www.xtuple.org/xtincident/view/bugs/20868)
-  _-k flag for build_app_
-- Implemented
-  issue #[20874](http://www.xtuple.org/xtincident/view/bugs/20874)
-  _Merge time and expense functionality into project_
-- Fixed
-  issue #[20999](http://www.xtuple.org/xtincident/view/bugs/20999)
-  _support build_app with absolute -c path_
-- Fixed
-  issue #[21007](http://www.xtuple.org/xtincident/view/bugs/21007)
-  _Sales Analysis does not display correct Cube after changing databases_
-
-Critical deployment changes
----------------------------
-* We have moved the test folder from the node-datasource directory.
-  You will want to move by hand the two gitignored files in there:
-  demo-test.backup, and login_data.js. Then, you can rmdir the
-  `node-datasource/test` folder and all its subfolders.
-* The init_scripts and the command-line ORM installer are gone.
-  You will have to use /scripts/build_app.js for your installation needs.
-  Run it with the -h flag to see the options.
-* The old tools for building client code (deploy.sh, buildExtensions.sh, build_client.js)
-  are gone. Use /scripts/build_app.js for your client-building needs.
-  Run it with the -h flag to see the options.
-* When you merge from master git will complain that it is not able to delete
-  an enyo directory which has just be deinitialized as a submodule. You will
-  want to delete it by hand. This goes for the xtuple and the private-extensions repos.
-
-
-1.3.9 (2013/06/27)
-==================
-
-Features and bugfixes
-----------------
-- Fixed
-  issue #[18845](http://www.xtuple.org/xtincident/view/bugs/18845)
-  _Status is missing from To Do_
-- Fixed
-  issue #[19271](http://www.xtuple.org/xtincident/view/bugs/19271)
-  _Datasource does not enforce privilege extensions on fetch_
-- Fixed
-  issue #[19272](http://www.xtuple.org/xtincident/view/bugs/19272)
-  _Half-drilldown into deprivileged workspaces_
-- Fixed
-  issue #[19797](http://www.xtuple.org/xtincident/view/bugs/19797)
-  _Quote shows margin when user does not have show margin privilege_
-- Fixed
-  issue #[20074](http://www.xtuple.org/xtincident/view/bugs/20074)
-  _*Irrelevant behavior is observed in Quote line items_
-- Fixed
-  issue #[20204](http://www.xtuple.org/xtincident/view/bugs/20204)
-  _Mobile client unaware of public/private comments_
-- Fixed
-  issue #[20272](http://www.xtuple.org/xtincident/view/bugs/20272)
-  _Relation widget keeps appending parameters_
-- Fixed
-  issue #[20332](http://www.xtuple.org/xtincident/view/bugs/20332)
-  _Error Adding a Sales Order to an Opportunity_
-- Fixed
-  issue #[20333](http://www.xtuple.org/xtincident/view/bugs/20333)
-  _Advanced Seach of Sales Rep on Sales Order does not work correctly_
-- Fixed
-  issue #[20356](http://www.xtuple.org/xtincident/view/bugs/20356)
-  _Calendar still active after date is picked_
-- Implemented
-  issue #[20373](http://www.xtuple.org/xtincident/view/bugs/20373)
-  _Bring back DisableExport_
-- Implemented
-  issue #[20375](http://www.xtuple.org/xtincident/view/bugs/20375)
-  _Bring back priv_group_
-- Fixed
-  issue #[20440](http://www.xtuple.org/xtincident/view/bugs/20440)
-  _Incident Documents double when using Apply_
-- Fixed
-  issue #[20456](http://www.xtuple.org/xtincident/view/bugs/20456)
-  _Clicking on Locked Icon gives Console error_
-- Fixed
-  issue #[20476](http://www.xtuple.org/xtincident/view/bugs/20476)
-  _Tax Assignemnt gives Java Console Error_
-- Fixed
-  issue #[20501](http://www.xtuple.org/xtincident/view/bugs/20501)
-  _ToDo and Prospect form report routes_
-- Fixed
-  issue #[20506](http://www.xtuple.org/xtincident/view/bugs/20506)
-  _Add multi-tenant support for Pentaho reports_
-- Fixed
-  issue #[20540](http://www.xtuple.org/xtincident/view/bugs/20540)
-  _User Account Roles do not use groups_
-- Fixed
-  issue #[20549](http://www.xtuple.org/xtincident/view/bugs/20549)
-  _You should be able to assign extensions in user accunt roles as well as user accounts_
-- Fixed
-  issue #[20555](http://www.xtuple.org/xtincident/view/bugs/20555)
-  _new authentication does not work with pgbouncer_
-- Fixed
-  issue #[20563](http://www.xtuple.org/xtincident/view/bugs/20563)
-  _Action - Change Password requires 6 digits_
-- Fixed
-  issue #[20583](http://www.xtuple.org/xtincident/view/bugs/20583)
-  _Authentication not remembered_
-- Fixed
-  issue #[20601](http://www.xtuple.org/xtincident/view/bugs/20601)
-  _There is no tracking of version numbers in extensions_
-- Fixed
-  issue #[20609](http://www.xtuple.org/xtincident/view/bugs/20609)
-  _Incident plus broken_
-- Fixed
-  issue #[20637](http://www.xtuple.org/xtincident/view/bugs/20637)
-  _The attach button should not be available on Customer for Sales Orders and Quotes_
-- Fixed
-  issue #[20638](http://www.xtuple.org/xtincident/view/bugs/20638)
-  _Attach option on relation boxes should not display objects already attached to other objects_
-
-1.3.8 (2013/06/19)
-==================
-
-Features and bugfixes
-----------------
-- Fixed
-  issue #[20605](http://www.xtuple.org/xtincident/view/bugs/20605)
-  _Web client does not use the metric to determine the welcome page URL path_
-
-1.3.7 (2013/06/11)
-==================
-
-Features and bugfixes
-----------------
-- Fixed problem where user names that are email addresses could not log in.
-
-1.3.6 (2013/06/06)
-==================
-
-Features and bugfixes
-----------------
-* Fix critical user login problem
-- Fixed
-  issue #[20505](http://www.xtuple.org/xtincident/view/bugs/20505)
-  _Remove print menus and buttons until Pentaho service available on cloud deployment._
-
-1.3.5 (2013/05/31)
-===============
-
-Critical deployment changes
----------------------------
-* Add redirectPort and maintenancePort to config.js, see sample_config.js
-* To run tests you will need to add the test database to the login_data.js
-  file, per the conventions in sample_login_data.js. Note also the new
-  snake_case filename convention. You will also need to add this database
-  name to your config.js file under datasource.testDatabase.
-* Changed XT.Data's handling of Dates and nulls to work with current version of plv8
-  that doesn't require any special handling. You need to be on this plv8 version:
-
-> commit d75184e00e08e97bc8caba6c9677f8f375a051aa
-
-> Date:   Wed Feb 20 00:10:56 2013 -0800
-
-  To find your current plv8 version:
-
-      cd ~/plv8js
-      git log -1
-
-  To move to that plv8 from your current:
-
-      mv plv8js plv8js-old
-      git clone https://code.google.com/p/plv8js/
-      cd plv8js
-      git checkout d75184e00e08e97bc8caba6c9677f8f375a051aa
-      # Make sure this is the path to your V8 source:
-      make V8_SRCDIR=/home/dev/v8
-      sudo make install
-      # Restart PostgreSQL Server
-      sudo /etc/init.d/postgresql restart
-
-  To test if your plv8 is working correctly, try adding a comment to an Account or Contact.
-  See if you get any errors in your browsers Javascript Console and make sure the comment saves.
-
-Features and bugfixes
-----------------
-
-- Implemented parts of
-  issue #[20264](http://www.xtuple.org/xtincident/view/bugs/20264)
-  REST - Refactor error handling in the database layer
-- Fixed
-  issue #[20448](http://www.xtuple.org/xtincident/view/bugs/20448)
-  _Entering wrong password on mobile client does not return error_
-- Fixed
-  issue #[20441](http://www.xtuple.org/xtincident/view/bugs/20441)
-  _Redirect Port other than 80 does not work_
-- Fixed
-  issue #[20347](http://www.xtuple.org/xtincident/view/bugs/20347)
-  _Default country not working on CRM configuration_
-- Fixed
-  issue #[20319](http://www.xtuple.org/xtincident/view/bugs/20319)
-  _Unable to select first menu after selecting a different menu option_
-- Fixed
-  issue #[20310](http://www.xtuple.org/xtincident/view/bugs/20310)
-  _Next number is a formatted number in sales config_
-- Fixed
-  issue #[20307](http://www.xtuple.org/xtincident/view/bugs/20307)
-  _Can't attach multiple customers to group_
-- Fixed
-  issue #[20297](http://www.xtuple.org/xtincident/view/bugs/20297)
-  _JSON-Patch needs to point to http, not git_
-- Implemented
-  issue #[20295](http://www.xtuple.org/xtincident/view/bugs/20295)
-  _move all ports into config.js_
-- Fixed
-  issue #[20270](http://www.xtuple.org/xtincident/view/bugs/20270)
-  _*Omnibus :Description label is displayed incorrectly_
-- Fixed
-  issue #[20266](http://www.xtuple.org/xtincident/view/bugs/20266)
-  _SQL Injection exploit in XT.Data_
-- Implemented
-  issue #[20254](http://www.xtuple.org/xtincident/view/bugs/20254)
-  _Integrate web-mobile user management into the application database_
-- Fixed
-  issue #[20240](http://www.xtuple.org/xtincident/view/bugs/20240)
-  _Updating ORM uses Username instead of specified -u user_
-- Implemented
-  issue #[20212](http://www.xtuple.org/xtincident/view/bugs/20212)
-  _Build out time and expense portion of "PPM"_
-- Fixed
-  issue #[20208](http://www.xtuple.org/xtincident/view/bugs/20208)
-  _User account assignment box is broken_
-- Fixed
-  issue #[20199](http://www.xtuple.org/xtincident/view/bugs/20199)
-  _Unable to select line item for a quote_
-- Fixed
-  issue #[20180](http://www.xtuple.org/xtincident/view/bugs/20180)
-  _*It is not possible to filter the Customers screen using Advanced Search window_
-- Fixed
-  issue #[20177](http://www.xtuple.org/xtincident/view/bugs/20177)
-  _* It is not possible to assign 'Tax Authority' role to a CRM Account_
-- Fixed
-  issue #[20162](http://www.xtuple.org/xtincident/view/bugs/20162)
-  _*Text box is displayed irrelevantly for the Currency field in the Tax Rate screen_
-- Fixed
-  issue #[20157](http://www.xtuple.org/xtincident/view/bugs/20157)
-  _Incident relations not showing_
-- Fixed
-  issue #[20078](http://www.xtuple.org/xtincident/view/bugs/20078)
-  _Priv Error when trying to add a custom command_
-- Implemented
-  issue #[20052](http://www.xtuple.org/xtincident/view/bugs/20052)
-  _Tax rate ORM, model, and views need to be added_
-- Implemented
-  issue #[20041](http://www.xtuple.org/xtincident/view/bugs/20041)
-  _build extensions dynamically through node_
-- Implemented
-  issue #[20040](http://www.xtuple.org/xtincident/view/bugs/20040)
-  _Add support for Sales Orders_
-- Fixed
-  issue #[20026](http://www.xtuple.org/xtincident/view/bugs/20026)
-  _*Irrelevant behavior is observed on selecting to assign Tax Authority/Sales Rep role to a CRM account_
-- Fixed
-  issue #[20024](http://www.xtuple.org/xtincident/view/bugs/20024)
-  _*Omnibus : Records data  grayed out on editing and refreshing to save the changes made_
-- Fixed
-  issue #[20011](http://www.xtuple.org/xtincident/view/bugs/20011)
-  _*Chrome : Omnibus :Irrelavant dates are displayed on selecting to enter Date starting with special character_
-- Fixed
-  issue #[19976](http://www.xtuple.org/xtincident/view/bugs/19976)
-  _Quote for prospect requires ship-to_
-- Fixed
-  issue #[19970](http://www.xtuple.org/xtincident/view/bugs/19970)
-  _Cannot open an Opportunity from a To Do_
-- Fixed
-  issue #[19932](http://www.xtuple.org/xtincident/view/bugs/19932)
-  _Characteristics not completely working on quote_
-- Fixed
-  issue #[19889](http://www.xtuple.org/xtincident/view/bugs/19889)
-  _*Omnibus: Selecting to enter a number with more than 10 digits in 'Order' field shows irrelevant behavior_
-- Fixed
-  issue #[19888](http://www.xtuple.org/xtincident/view/bugs/19888)
-  _Unable to enter a number with more than 12 digits in the 'Expenses' section under the 'Project Tasks' widget of a Project screen_
-- Fixed
-  issue #[19871](http://www.xtuple.org/xtincident/view/bugs/19871)
-  _*Tab out from an Items 'Extended Description' field displays an irrelevant dialog_
-- Fixed
-  issue #[19844](http://www.xtuple.org/xtincident/view/bugs/19844)
-  _Clicking in Blank Space causes error_
-- Fixed
-  issue #[19833](http://www.xtuple.org/xtincident/view/bugs/19833)
-  _New privileges installed by packages do not appear_
-- Fixed
-  issue #[19830](http://www.xtuple.org/xtincident/view/bugs/19830)
-  _The advanced search box is wider than the panel_
-- Implemented
-  issue #[19795](http://www.xtuple.org/xtincident/view/bugs/19795)
-  _Numbers on number widgets should be right justified_
-- Fixed
-  issue #[19677](http://www.xtuple.org/xtincident/view/bugs/19677)
-  _*It is possible to enter 'End Date'  prior to 'Start Date' for a Tax Registration Number under 'Tax Registration Numbers' widget_
-- Fixed
-  issue #[19676](http://www.xtuple.org/xtincident/view/bugs/19676)
-  _* Omnibus: Discarding the changes made in a Project Task shows unexpected behaviour_
-- Fixed
-  issue #[19658](http://www.xtuple.org/xtincident/view/bugs/19658)
-  _* Omnibus :'To Do' associated to the 'Customer' is displayed as locked on selecting to open_
-- Fixed
-  issue #[19632](http://www.xtuple.org/xtincident/view/bugs/19632)
-  _*Unable to attach a new file to a record_
-- Fixed
-  issue #[19616](http://www.xtuple.org/xtincident/view/bugs/19616)
-  _*Back button is not working on selecting to discard the changes made in a CRM Account's Role_
-- Fixed
-  issue #[19599](http://www.xtuple.org/xtincident/view/bugs/19599)
-  _Maxhammer Mobile Users created with improper SUPERUSER roles and overview of proper db creation process._
-- Fixed
-  issue #[19542](http://www.xtuple.org/xtincident/view/bugs/19542)
-  _Shipping charges prevent customer edit_
-- Fixed
-  issue #[19471](http://www.xtuple.org/xtincident/view/bugs/19471)
-  _Unable to create custom commands in dogfood_
-- Fixed
-  issue #[19045](http://www.xtuple.org/xtincident/view/bugs/19045)
-  _ Omnibus : Database error is displayed on selecting to duplicate existing records_
-- Fixed
-  issue #[19033](http://www.xtuple.org/xtincident/view/bugs/19033)
-  _Irrelavant behaviour is observed in Project task screen_
-- Fixed
-  issue #[18958](http://www.xtuple.org/xtincident/view/bugs/18958)
-  _Errors preventing creation of new item_
-- Implemented
-  issue #[18757](http://www.xtuple.org/xtincident/view/bugs/18757)
-  _REST - Modify the XT.Data commit code to enforce the new requiredAttributes driven by db NOT NULL and ORM override_
-
-
-1.3.4 (2013/05/06)
-===============
-
-Features and bugfixes
------------------
-- Fixed
-  issue #[20169](http://www.xtuple.org/xtincident/view/bugs/20169)
-  _etag versions not working with usr and org string pkeys_
-- Implemented
-  issue #[18716](http://www.xtuple.org/xtincident/view/bugs/18716)
-  _REST - Create helper functions needed to generate API Directory list and Discovery Documents_
-- Implemented
-  issue #[19304](http://www.xtuple.org/xtincident/view/bugs/19304)
-  _REST - Add route generator for resource end points_
-- Fixed
-  issue #[19870](http://www.xtuple.org/xtincident/view/bugs/19870)
-  _Unable to attach a contact related to a CRM Account under Documents widget of an accounts screen_
-- Fixed
-  issue #[19905](http://www.xtuple.org/xtincident/view/bugs/19905)
-  _Documents attached under the document widget of a record are not displayed on selecting to reopen the record_
-- Fixed
-  issue #[20214](http://www.xtuple.org/xtincident/view/bugs/20214)
-  _incorrect login brings up error screen_
-- Fixed
-  issue #[20235](http://www.xtuple.org/xtincident/view/bugs/20235)
-  _Selecting to enter the address for a contact displays an error message in the console_
-- Fixed
-  issue #[20205](http://www.xtuple.org/xtincident/view/bugs/20205)
-  _Select Organization for a User - "ID is required" Error_
-- Fixed
-  issue #[20184](http://www.xtuple.org/xtincident/view/bugs/20184)
-  _List lazy-loading problem_
-- Fixed
-  issue #[19953](http://www.xtuple.org/xtincident/view/bugs/19953)
-  _Cannot use a prospect to save a quote_
-- Fixed
-  issue #[19973](http://www.xtuple.org/xtincident/view/bugs/19973)
-  _percent widget is broken_
-- Fixed
-  issue #[20026](http://www.xtuple.org/xtincident/view/bugs/20026)
-  _*Irrelevant behavior is observed on selecting to assign Tax Authority/Sales Rep role to a CRM account_
-- Implemented
-  issue #[20154](http://www.xtuple.org/xtincident/view/bugs/20154)
-  _Add support for natural keys on orms_
-- Fixed
-  issue #[20066](http://www.xtuple.org/xtincident/view/bugs/20066)
-  _*Irrelevant dialog is displayed on selecting to save a Tax Class_
-- Implemented
-  issue #[20044](http://www.xtuple.org/xtincident/view/bugs/20044)
-  _Add support JSON Patch_
-- Implemented
-  issue #[20052](http://www.xtuple.org/xtincident/view/bugs/20052)
-  _Tax rate ORM, model, and views need to be added_
-- Implemented
-  issue #[20054](http://www.xtuple.org/xtincident/view/bugs/20054)
-  _installer should work atomically on one org at a time_
-
-
-1.3.3 (2013/04/18)
-===============
-
-Critical deployment changes
----------------------------
-* You need to add
-  <code>"lib/ext/smtpTransport"</code>
-  as a requirement in your config.js. See
-  [sample_config.js](https://github.com/xtuple/xtuple/blob/master/node-datasource/sample_config.js) for details.
-* We removed node-datasource/lib/private/salt.txt from version control. You
-  will have to put this file back in yourself. You can fill it with any long string you want.
-* You need to implement npm changes, config.js changes, and the deletion of a global table as documented
-  [here](https://github.com/xtuple/xtuple/pull/224).
-* We are now running on [our own fork of plv8](https://github.com/xtuple/plv8).
-
-
-Features and bugfixes
------------------
-- Fixed
-  issue #[19246](http://www.xtuple.org/xtincident/view/bugs/19246)
-  _Help file iframe issue on Firefox_
-- Fixed
-  issue #[19593](http://www.xtuple.org/xtincident/view/bugs/19593)
-  _Record Lock - No Error when attaching a Locked Contact to Account_
-- Fixed
-  issue #[19450](http://www.xtuple.org/xtincident/view/bugs/19450)
-  _Updating setup items does not update their collections and pickers_
-- Fixed
-  issue #[19469](http://www.xtuple.org/xtincident/view/bugs/19469)
-  _customer edit ship-to bug_
-- Implemented
-  issue #[19442](http://www.xtuple.org/xtincident/view/bugs/19442)
-  _Add schema to data routes for Pentaho reports_
-- Implemented
-  issue #[19296](http://www.xtuple.org/xtincident/view/bugs/19296)
-  _OAuth 2.0 - After switching to ONLY Express, remove dead code in node-xt and node-datasource_
-- Fixed
-  issue #[19813](http://www.xtuple.org/xtincident/view/bugs/19813)
-  _Create list and view to maintain customer groups_
-- Implemented
-  issue #[19812](http://www.xtuple.org/xtincident/view/bugs/19812)
-  _Create list and view to maintain customer types_
-- Implemented
-  issue #[19818](http://www.xtuple.org/xtincident/view/bugs/19818)
-  _List cost should be added to item workspace_
-- Implemented
-  issue #[19811](http://www.xtuple.org/xtincident/view/bugs/19811)
-  _Create list and view to maintain sales reps_
-- Implemented
-  issue #[19847](http://www.xtuple.org/xtincident/view/bugs/19847)
-  _Additional mobile db Org Attributes Fields/tables to support automation and data collection required for campaigns etc._
-- Implemented
-  issue #[19815](http://www.xtuple.org/xtincident/view/bugs/19815)
-  _Create list and workspace for freight class_
-- Implemented
-  issue #[19821](http://www.xtuple.org/xtincident/view/bugs/19821)
-  _Create list and workspace for ship zone_
-- Fixed
-  issue #[19840](http://www.xtuple.org/xtincident/view/bugs/19840)
-  _Quotes panel MISSING on Opportunity, Prospect and Customer_
-- Fixed
-  issue #[20007](http://www.xtuple.org/xtincident/view/bugs/20007)
-  _Parent CRM account not created when prospect created_
-- Implemented
-  issue #[19814](http://www.xtuple.org/xtincident/view/bugs/19814)
-  _Create list and views for tax maintenance_
-- Implemented
-  issue #[19822](http://www.xtuple.org/xtincident/view/bugs/19822)
-  _Create list and workspace for terms_
-- Fixed
-  issue #[20022](http://www.xtuple.org/xtincident/view/bugs/20022)
-  _Project numbers are disabled in incidents_
-- Fixed
-  issue #[19703](http://www.xtuple.org/xtincident/view/bugs/19703)
-  _speed up update_
-- Implemented
-  issue #[19972](http://www.xtuple.org/xtincident/view/bugs/19972)
-  _Proposal for BI for Sales based on Pentaho Community_
-- Fixed
-  issue #[19806](http://www.xtuple.org/xtincident/view/bugs/19806)
-  _Quote summary needs cosmetic work_
-- Fixed
-  issue #[19930](http://www.xtuple.org/xtincident/view/bugs/19930)
-  _Search on Address in Quote does not work_
-- Implemented
-  issue #[19989](http://www.xtuple.org/xtincident/view/bugs/19989)
-  _Add a section to display version number_
-- Implemented
-  issue #[19823](http://www.xtuple.org/xtincident/view/bugs/19823)
-  _Create list and workspace for sale type_
-- Fixed
-  issue #[20039](http://www.xtuple.org/xtincident/view/bugs/20039)
-  _State Dropdown does not appear correctly when editing Ship-To_
-- Fixed
-  issue #[19804](http://www.xtuple.org/xtincident/view/bugs/19804)
-  _Cost on quote line items should show the local currency_
-- Implemented
-  issue #[20053](http://www.xtuple.org/xtincident/view/bugs/20053)
-  _Incident filter by foundIn and fixedIn_
-- Fixed
-  issue #[20067](http://www.xtuple.org/xtincident/view/bugs/20067)
-  _Customer Groups does not give error when saving with Blank Name_
-- Fixed
-  issue #[20073](http://www.xtuple.org/xtincident/view/bugs/20073)
-  _Numerous problems with customer shipto_
index adb4dc2..02e2565 160000 (submodule)
@@ -1 +1 @@
-Subproject commit adb4dc23d096bb1648b8369e5da0ca39e43b1e0d
+Subproject commit 02e25652e3d81f694919f917fb9eb23105befaeb
index e22a865..4e86c70 100644 (file)
@@ -15,7 +15,6 @@
     // Models
     // ********
 
-    "_analysis": "Analysis",
     "_all": "All",
     "_annualy": "Annually",
     "_asset": "Asset",
     "_closeDate": "Close Date",
     "_code": "Code",
     "_configure": "Configure",
+    "_commandCenter": "Command Center",
     "_commentType": "Comment Type",
     "_commentsEditable": "Comments Editable",
     "_company": "Company",
     "_extendedPrice": "Extended Price",
     "_extendedDescription": "Extended Description",
     "_extendedPriceScale": "Extended Price Scale",
+    "_extensionName": "Extension Name",
     "_externalReference": "External Reference",
     "_delivery": "Delivery",
     "_department": "Department",
     "_invoiceNumber": "Invoice #",
     "_invoices": "Invoices",
     "_initials": "Initials",
+    "_installExtension": "Install Extension",
     "_inventoryUnit": "Inventory Unit",
     "_isActive": "Active",
     "_isAddresses": "Addresses",
     "_subtotal": "Subtotal",
     "_suffix": "Suffix",
     "_summary": "Summary",
+    "_success!": "Success!",
     "_successors": "Successors",
     "_symbol": "Symbol",
     "_system": "System",
     "_thisWeek": "This Week",
     "_thisMonth": "This Month",
     "_thisYear": "This Year",
+    "_transactionKey": "Transaction Key",
     "_twoYears": "Two Years",
     "_to": "To",
     "_toDate": "To Date",
     "_customerOrProspect": "Would you like to create a new Customer or a new Prospect?",
     "_deleteLine?": "Are you sure you want to delete this line?",
     "_exitPageWarning": "You are about to leave the xTuple application.",
+    "_installExtensionWarning": "Extensions are very powerful and potentially have full access to your " +
+      "data. You should only install an extension from a source you trust. ",
     "_insufficientPrivileges": "You have insufficient privileges to perform this action.",
     "_manualFreight": "Manually editing the freight will disable automatic freight recalculations.",
     "_mustSave": "You must save your changes before proceeding.",
index 8a216b1..554e05f 100644 (file)
@@ -206,7 +206,7 @@ white:true*/
                   XM.jsonpatch.apply(attrs, data.patches);
                   cModel.etag = data.etag;
 
-                  // This is a hack to work around Backbone messing with 
+                  // This is a hack to work around Backbone messing with
                   // attributes when we don't want it to. Parse function
                   // on model handles the other side of this
                   options.fixAttributes = cModel.attributes;
@@ -259,7 +259,8 @@ white:true*/
       // handle error
       if (inResponse.isError) {
         if (inSender.error) {
-          params.error = inResponse.message;
+          // inResponse.message sometimes gets lost in the vagaries of socket-io
+          params.error = inResponse.message || inResponse.errorMessage;
           error = XT.Error.clone('xt1001', { params: params });
           inSender.error.call(this, error);
         }
index 46cef52..65a80c2 100644 (file)
@@ -22,6 +22,8 @@ white:true*/
     },
 
     _didValidateSession: function (payload, callback) {
+      var coreVersion;
+
       if (payload.code === 1) {
         // If this is a valid session acquisition, go ahead
         // and store the database config details in
@@ -30,10 +32,28 @@ white:true*/
         this.setConfig(payload);
         this.setDetails(payload.data);
 
-        if (payload.version && XT.setVersion) {
+        if (payload.versions && XT.setVersion) {
           // announce to the client what our version is, if we have
           // a way of doing it.
-          XT.setVersion(payload.version);
+
+          _.each(payload.versions,  function (version, extensionName) {
+            // default to the core version (temp until all core extensions are in npm)
+            if (extensionName === "core") {
+              coreVersion = version;
+              extensionName = "";
+            } else if (version === "none") {
+              version = coreVersion;
+            }
+
+            var aboutVersionLabel = XT.app.$.postbooks.$.navigator.$.aboutVersion,
+              versionText = extensionName + " " + "_version".loc().toLowerCase() + " " + version;
+
+            if (aboutVersionLabel.getContent()) {
+              versionText = aboutVersionLabel.getContent() + "<br>" + versionText;
+            }
+
+            aboutVersionLabel.setContent(versionText);
+          });
         }
 
         // Start the client loading process.
index f15e09a..c3ae3c8 100644 (file)
@@ -125,6 +125,14 @@ white:true*/
         params.length = "3";
         return XT.Error.clone('xt1006', { params: params });
       }
+
+      if (attributes.currencyNumber &&
+          attributes.currencyNumber.length !== 3) {
+        params.attr = "_currencyNumber".loc();
+        params.length = "3";
+        return XT.Error.clone('xt1006', { params: params });
+      }
+
       return XM.Document.prototype.validate.apply(this, arguments);
     }
 
index df7bc72..77d5e7f 100644 (file)
@@ -161,7 +161,7 @@ white:true*/
     },
 
     assignedToDidChange: function (model, value, options) {
-      if (value) {
+      if (value && this.get("status") !== XM.Incident.RESOLVED && this.get("status") !== XM.Incident.CLOSED) {
         this.set('status', XM.Incident.ASSIGNED);
       }
     },
index e7a2865..43f422d 100644 (file)
@@ -259,7 +259,7 @@ white:true*/
       var isPosted = this.get("isPosted");
 
       this.setReadOnly(["lineItems", "number", this.documentDateKey, "salesRep", "commission",
-        "taxZone", "saleType", "taxAdjustments"], isPosted);
+        "taxZone", "saleType", "taxAdjustments", "miscCharge"], isPosted);
 
       if (_.contains(this.getAttributeNames(), "terms")) {
         this.setReadOnly("terms", isPosted);
index b1d98ec..3f30871 100644 (file)
@@ -196,32 +196,6 @@ white:true*/
       return defaults;
     },
 
-    destroy: function (options) {
-      var status = this.getParent().get("status"),
-        K = XM.SalesOrder,
-        that = this,
-        payload = {
-          type: K.QUESTION,
-        },
-        args = arguments,
-        message;
-
-      if (status !== K.CLOSED_STATUS &&
-        status !== K.CANCELLED_STATUS) {
-        message = "_deleteLine?".loc();
-        payload.callback = function (response) {
-          if (response.answer) {
-            XM.Model.prototype.destroy.apply(that, args);
-          }
-        };
-      } else {
-        // Must be closed, shouldn't have come here.
-        return;
-      }
-
-      this.notify(message, payload);
-    },
-
     isActive: function () {
       return this.get("status") === XM.SalesOrder.OPEN_STATUS;
     }
index 5ed3085..4597280 100644 (file)
@@ -93,7 +93,15 @@ white:true*/
 
     recordType: 'XM.SiteListItem',
 
-    editableModel: 'XM.Site'
+    editableModel: 'XM.Site',
+
+    couldCreate: function () {
+      // Look to see if there are sites in the sites cache. If so, restrict new for Postbooks.
+      if (!XM.sites.length) {
+        return XM.Info.prototype.couldCreate.apply(this, arguments);
+      }
+      return false;
+    }
 
   });
 
index 813e23f..9e75865 100644 (file)
@@ -26,20 +26,8 @@ XT = typeof XT !== 'undefined' ? XT : {};
   };
 
   XT.setVersion = function (version, qualifier) {
-    // default to the core version
-    version = version || XT.session.config.version;
-
-    var aboutVersionLabel = XT.app.$.postbooks.$.navigator.$.aboutVersion,
-      versionText = "_version".loc() + " " + version;
-
-    if (qualifier) {
-      versionText = ("_" + qualifier).loc() + " " + versionText;
-    }
-    if (aboutVersionLabel.getContent()) {
-      versionText = aboutVersionLabel.getContent() + "<br>" + versionText;
-    }
-
-    aboutVersionLabel.setContent(versionText);
+    XT.log("XT.setVersion is now deprecated. The app now reads extension versions from " +
+      "package.json or manifest.js (" + qualifier + ")");
   };
 
 }());
index 7a7a2df..895065a 100644 (file)
@@ -23,6 +23,7 @@ white:true*/
         success: _.bind(this.didComplete, this)
       };
       var relevantPrivileges = [
+        "InstallExtension",
         "MaintainUsers",
         "MaintainPreferencesSelf",
         "MaintainWorkflowsSelf",
index aa5b973..b32de15 100644 (file)
@@ -690,10 +690,13 @@ trailing:true, white:true, strict: false*/
             {kind: "XV.ListAttr", attr: "billingContact.phone", },
             {kind: "XV.ListAttr", attr: "billingContact.primaryEmail"}
           ]},
-          {kind: "XV.ListColumn", fit: true, components: [
+          {kind: "XV.ListColumn", classes: "descr", components: [
             {kind: "XV.ListAttr", attr: "billingContact.name",
               placeholder: "_noContact".loc()},
             {kind: "XV.ListAttr", attr: "billingContact.address"}
+          ]},
+          {kind: "XV.ListColumn", fit: true, components: [
+            {kind: "XV.ListAttr", attr: "customerType.code"}
           ]}
         ]}
       ]}
@@ -2531,7 +2534,7 @@ trailing:true, white:true, strict: false*/
       ]}
     ]
   });
-  
+
   XV.registerModelList("XM.UserAccountRelation", "XV.UserAccountList");
 
   // ..........................................................
index cc2cb7b..afaf261 100644 (file)
@@ -65,7 +65,7 @@ trailing:true, white:true*/
       this.$.buttonsPanel.createComponent({
         kind: "onyx.Button",
         name: "processButton",
-        showing: false,
+        disabled: true,
         ontap: "processCreditCard",
         classes: "onyx-affirmative",
         content: "_process".loc()
@@ -73,7 +73,7 @@ trailing:true, white:true*/
       this.$.buttonsPanel.createComponent({
         kind: "onyx.Button",
         name: "authorizeButton",
-        showing: false,
+        disabled: true,
         ontap: "processCreditCard",
         content: "_authorize".loc()
       }, {owner: this});
@@ -84,7 +84,7 @@ trailing:true, white:true*/
     newItem: function (options) {
       options = options || {};
       var that = this,
-        // XXX #refactor 
+        // XXX #refactor
         customer = that.parent.parent.getValue().getValue("customer"),
         creditCardCollection = customer.get("creditCards"),
         creditCardModel = new XM.CreditCard(),
@@ -201,8 +201,8 @@ trailing:true, white:true*/
           // XXX #refactor
           payload.orderNumber = that.parent.parent.getValue().id;
           payload.customerNumber = that.parent.parent.getValue().getValue("customer.id");
-          that.$.authorizeButton.setShowing(false);
-          that.$.processButton.setShowing(false);
+          that.$.authorizeButton.setDisabled(true);
+          that.$.processButton.setDisabled(true);
           XT.dataSource.callRoute("credit-card", payload, {success: success, error: error});
         };
 
@@ -226,10 +226,17 @@ trailing:true, white:true*/
       var list = this.$.list,
         creditCard = list.getModel(list.getFirstSelected()),
         ccv = this.$.ccv.value,
-        amount = this.$.creditCardAmount.value;
-
-      this.$.processButton.setShowing(creditCard && amount && (ccv || !XT.session.settings.get("CCRequireCCV")));
-      this.$.authorizeButton.setShowing(creditCard && amount && (ccv || !XT.session.settings.get("CCRequireCCV")));
+        amount = this.$.creditCardAmount.value,
+        disable = !creditCard ||
+          !amount ||
+          (!ccv && !!XT.session.settings.get("CCRequireCCV")) ||
+          // XXX refactor after attributesChanged refactor
+          // this kind should hold onto a reference to the model
+          // that backs the workspace
+          this.parent.parent.value.isNew();
+
+      this.$.processButton.setDisabled(disable);
+      this.$.authorizeButton.setDisabled(disable);
       return true;
     }
   });
index 64c7a96..f74658d 100644 (file)
@@ -430,9 +430,62 @@ strict: false*/
             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
             {kind: "XV.TextArea", attr: "DatabaseComments"}
           ]}
+        ]},
+        {kind: "XV.Groupbox",
+          title: "_commandCenter".loc(), name: "commandPanel", components: [
+          {kind: "XV.ScrollableGroupbox",
+            classes: "in-panel", components: [
+            {kind: "onyx.GroupboxHeader", content: "_installExtension".loc()},
+            {kind: "XV.InputWidget", name: "extensionName", label: "_extensionName".loc()},
+            {kind: "FittableColumns", classes: "xv-buttons center", components: [
+              {kind: "onyx.Button", name: "extensionButton", classes: "icon-ok", ontap: "installExtension"},
+            ]},
+          ]}
         ]}
       ]}
-    ]
+    ],
+    create: function () {
+      this.inherited(arguments);
+      var hasPriv = XT.session.privileges.get("InstallExtension");
+      this.$.extensionName.setDisabled(!hasPriv);
+      this.$.extensionButton.setDisabled(!hasPriv);
+    },
+    installExtension: function () {
+      var that = this,
+        callback = function (response) {
+          if (!response.answer) {
+            return;
+          }
+
+          XT.dataSource.callRoute("install-extension",
+            {
+              extensionName: that.$.extensionName.getValue()
+            },
+            {
+              success: function (message) {
+                that.doNotify({message: message && message.loc()});
+              },
+              error: function (error) {
+                that.doNotify({message: error.message ? error.message() : error});
+              }
+            }
+          );
+        };
+
+      if (!this.$.extensionName.getValue()) {
+        this.doNotify({
+          type: XM.Model.WARNING,
+          message: "_attributeIsRequired".loc().replace("{attr}", "_extensionName".loc())
+        });
+        return;
+      }
+
+      this.doNotify({
+        type: XM.Model.QUESTION,
+        message: "_installExtensionWarning".loc() + "_confirmAction".loc(),
+        callback: callback
+      });
+    }
   });
 
   enyo.kind({
@@ -455,7 +508,7 @@ strict: false*/
             {kind: "XV.InputWidget", attr: "CCLogin",
               label: "_login".loc()},
             {kind: "XV.InputWidget", attr: "CCPassword",
-                label: "_password".loc()},
+                label: "_transactionKey".loc()},
             {kind: "XV.ToggleButtonWidget", attr: "CCTest",
                 label: "_testMode".loc()},
             {kind: "XV.ToggleButtonWidget", attr: "CCRequireCCV",
@@ -588,12 +641,12 @@ strict: false*/
           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
             classes: "in-panel", components: [
-            {kind: "XV.InputWidget", attr: "abbreviation"},
+            {kind: "XV.InputWidget", attr: "abbreviation", maxlength: 2},
             {kind: "XV.InputWidget", attr: "name"},
             {kind: "XV.InputWidget", attr: "currencyName"},
             {kind: "XV.InputWidget", attr: "currencySymbol"},
-            {kind: "XV.InputWidget", attr: "currencyAbbreviation"},
-            {kind: "XV.InputWidget", attr: "currencyNumber"}
+            {kind: "XV.InputWidget", attr: "currencyAbbreviation", maxlength: 3},
+            {kind: "XV.InputWidget", attr: "currencyNumber", maxlength: 3}
           ]}
         ]}
       ]}
@@ -1252,7 +1305,7 @@ strict: false*/
                   city: "billtoCity", state: "billtoState",
                   postalCode: "billtoPostalCode", country: "billtoCountry"}
               },
-              {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
+              {kind: "onyx.GroupboxHeader", content: "_notes".loc(), name: "notesHeader"},
               {kind: "XV.TextArea", attr: "notes", fit: true}
             ]}
           ]}
@@ -1283,12 +1336,12 @@ strict: false*/
       this.inherited(arguments);
       if (enyo.platform.touch) {
         this.$.panels.createComponents([
-          {kind: "XV.InvoiceLineItemBox", name: "invoiceLineItemBox", attr: "lineItems",
+          {kind: "XV.InvoiceLineItemBox", name: "lineItemBox", attr: "lineItems",
             title: "_lineItems".loc(), addBefore: this.$.settingsPanel, classes: "medium-panel"}
         ], {owner: this});
       } else {
         this.$.panels.createComponents([
-          {kind: "XV.InvoiceLineItemGridBox", name: "invoiceLineItemBox", title: "_lineItems".loc(),
+          {kind: "XV.InvoiceLineItemGridBox", name: "lineItemBox", title: "_lineItems".loc(),
             attr: "lineItems", addBefore: this.$.settingsPanel}
         ], {owner: this});
       }
@@ -1829,13 +1882,13 @@ strict: false*/
       this.inherited(arguments);
       if (enyo.platform.touch) {
         this.$.panels.createComponents([
-          {kind: "XV.ReturnLineItemBox", name: "returnLineItemBox",
+          {kind: "XV.ReturnLineItemBox", name: "lineItemBox",
             attr: "lineItems", title: "_lineItems".loc(),
               addBefore: this.$.settingsPanel, classes: "medium-panel"}
         ], {owner: this});
       } else {
         this.$.panels.createComponents([
-          {kind: "XV.ReturnLineItemGridBox", name: "returnLineItemBox",
+          {kind: "XV.ReturnLineItemGridBox", name: "lineItemBox",
             title: "_lineItems".loc(), attr: "lineItems", addBefore: this.$.settingsPanel}
         ], {owner: this});
       }
@@ -2732,19 +2785,17 @@ strict: false*/
           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
             classes: "in-panel", components: [
-            {kind: "XV.InputWidget", attr: "code"},
-            {kind: "XV.CheckboxWidget", attr: "isActive"},
-            {kind: "XV.SiteTypePicker", attr: "siteType"},
-            {kind: "XV.InputWidget", attr: "description"},
-            {kind: "XV.ContactWidget", attr: "contact"},
-            {kind: "XV.AddressWidget", attr: "address"},
-            {kind: "XV.TaxZonePicker", attr: "taxZone"},
-            {kind: "XV.InputWidget", attr: "incoterms"},
-            {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
-            {kind: "XV.TextArea", attr: "notes", fit: true}
+            {name: "mainSubgroup", components: [ // not a scroller, so we can addBefore
+              {kind: "XV.InputWidget", attr: "code"},
+              {kind: "XV.CheckboxWidget", attr: "isActive"},
+              {kind: "XV.SiteTypePicker", attr: "siteType"},
+              {kind: "XV.InputWidget", attr: "description"},
+              {kind: "XV.ContactWidget", attr: "contact", name: "contactWidget"},
+              {kind: "XV.AddressWidget", attr: "address"}
+            ]}
           ]}
         ]},
-        {kind: "XV.SiteCommentBox", attr: "comments"}
+        {kind: "XV.SiteCommentBox", attr: "comments", name: "commentsPanel"}
       ]}
     ]
   });
@@ -3292,5 +3343,4 @@ strict: false*/
   XV.registerModelWorkspace("XM.UserAccountRoleRelation", "XV.UserAccountRoleWorkspace");
   XV.registerModelWorkspace("XM.UserAccountRoleListItem", "XV.UserAccountRoleWorkspace");
 
-
 }());
index b051ef7..c5a0143 100644 (file)
@@ -90,7 +90,7 @@ white:true, strict:false*/
     name: "XV.OrderCharacteristicItem",
     kind: "XV.CharacteristicItem",
     components: [
-      {kind: "XV.ComboboxWidget", name: "combobox", attr: "value", style: "width: 300px"}
+      {kind: "XV.ComboboxWidget", name: "combobox", attr: "value"}
     ],
     disabledChanged: function (oldValue) {
       this.$.combobox.setDisabled(this.disabled);
index 71db45f..cf31b74 100644 (file)
@@ -47,7 +47,7 @@ regexp:true, undef:true, trailing:true, white:true */
       options = options || {};
       var isRelation = this.isRelation(),
         that = this,
-        color = "black",
+        colorClass = "",
         enabled = false,
         input = this.$.input.getValue(),
         openWorkspace,
@@ -64,10 +64,10 @@ regexp:true, undef:true, trailing:true, white:true */
 
       // Turn on label link if applicable
       if (this.getValue() && isRelation) {
-        color = "blue";
+        colorClass = "hyperlink";
         enabled = true;
       }
-      this.$.label.setStyle("color: " + color);
+      this.$.label.addClass(colorClass);
       this.setLinkEnabled(enabled);
       this.setDisabled(enabled);
 
index 9cb0add..58b2c66 100644 (file)
@@ -70,11 +70,9 @@ regexp:true, undef:true, trailing:true, white:true */
       this.inherited(arguments);
       this.createComponent({
         name: "comboboxNote",
-        container: this.$.fittableColumns,
+        container: this.$.container,
         classes: "xv-combobox-note"
       });
-      this.$.input.applyStyle("padding-top", "8px");
-      this.$.input.applyStyle("padding-left", "8px");
     },
     /**
       Populate the note field
index 86053f5..f29fce8 100644 (file)
@@ -33,29 +33,26 @@ regexp:true, undef:true, trailing:true, white:true */
     },
     maxlength: 12,
     components: [
-      {kind: "FittableColumns", components: [
+      {controlClasses: "enyo-inline", components: [
         {name: "label", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
+        {kind: "onyx.InputDecorator", components: [
           {name: "input", kind: "onyx.Input",
             onchange: "inputChanged", onkeydown: "keyDown"}
         ]},
-        {name: "picker", kind: "XV.CurrencyPicker", showLabel: false}
+        {name: "picker", kind: "XV.CurrencyPicker", classes: "xv-currency-picker", showLabel: false}
       ]},
-      {kind: "FittableColumns", name: "basePanel", showing: false,
-        components: [
-        {name: "spacer", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
-          {name: "baseAmountLabel", classes: "xv-money-label"}
+      {controlClasses: "enyo-inline", name: "basePanel", showing: false, components: [
+        {classes: "xv-label"},
+        {kind: "onyx.InputDecorator", components: [
+          {name: "baseAmountLabel", classes: "xv-label"}
         ]},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator, xv-currency-label",
-          components: [
-          {name: "baseCurrencyLabel"}
+        {classes: "xv-currency-picker", components: [
+          {kind: 'onyx.InputDecorator', components: [
+            {name: 'baseCurrencyLabel'}
+          ]}
         ]}
       ]}
     ],
-
     /**
       Set the base price into the base amount label
     */
index b8007c7..475a804 100644 (file)
@@ -8,12 +8,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // COST
   //
 
-  enyo.kind({
-    name: "XV.Cost",
-    kind: "XV.Number",
-    scale: XT.COST_SCALE
-  });
-
   enyo.kind({
     name: "XV.CostWidget",
     kind: "XV.NumberWidget",
@@ -24,12 +18,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // EXTENDED PRICE
   //
 
-  enyo.kind({
-    name: "XV.ExtendedPrice",
-    kind: "XV.Number",
-    scale: XT.EXTENDED_PRICE_SCALE
-  });
-
   enyo.kind({
     name: "XV.ExtendedPriceWidget",
     kind: "XV.NumberWidget",
@@ -40,13 +28,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // HOURS
   //
 
-  enyo.kind({
-    name: "XV.Hours",
-    kind: "XV.Number",
-    maxlength: 12,
-    scale: XT.HOURS_SCALE
-  });
-
   enyo.kind({
     name: "XV.HoursWidget",
     kind: "XV.NumberWidget",
@@ -58,28 +39,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // PERCENT
   //
 
-  enyo.kind({
-    name: "XV.Percent",
-    kind: "XV.Number",
-    scale: XT.PERCENT_SCALE,
-    validate: function (value) {
-      // this takes the string from the input field and parses it (including understanding commas, which isNaN cannot)
-      // if it cannot parse the value, it returns NaN
-      value = Globalize.parseFloat(value);
-      // use isNaN here because parseFloat could return NaN
-      // if you pass NaN into _.isNumber, it will misleadingly return true
-      // only bad string and null/undefined cases do we want to fail validation
-      return !isNaN(value) ? value / 100 : false;
-    },
-    valueChanged: function (value) {
-      // use isNaN here because this value may be a number string and _isNaN requires
-      // a separate falsy check.
-      // In this case, it is ok for 0 to fall to the true case, just not null or a bad string
-      value = !isNaN(value) ? value * 100 : value;
-      XV.Number.prototype.valueChanged.call(this, value);
-    }
-  });
-
   enyo.kind({
     name: "XV.PercentWidget",
     kind: "XV.NumberWidget",
@@ -106,12 +65,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // PURCHASE PRICE
   //
 
-  enyo.kind({
-    name: "XV.PurchasePrice",
-    kind: "XV.Number",
-    scale: XT.PURCHASE_PRICE_SCALE
-  });
-
   enyo.kind({
     name: "XV.PurchasePriceWidget",
     kind: "XV.NumberWidget",
@@ -122,13 +75,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // QUANTITY
   //
 
-  enyo.kind({
-    name: "XV.Quantity",
-    kind: "XV.Number",
-    maxlength: 12,
-    scale: XT.QTY_SCALE
-  });
-
   enyo.kind({
     name: "XV.QuantityWidget",
     kind: "XV.NumberWidget",
@@ -140,12 +86,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // QUANTITY PER
   //
 
-  enyo.kind({
-    name: "XV.QuantityPer",
-    kind: "XV.Number",
-    scale: XT.QTY_PER_SCALE
-  });
-
   enyo.kind({
     name: "XV.QuantityPerWidget",
     kind: "XV.NumberWidget",
@@ -156,12 +96,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // SALES PRICE
   //
 
-  enyo.kind({
-    name: "XV.SalesPrice",
-    kind: "XV.Number",
-    scale: XT.SALES_PRICE_SCALE
-  });
-
   enyo.kind({
     name: "XV.SalesPriceWidget",
     kind: "XV.NumberWidget",
@@ -172,12 +106,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // UNIT RATIO
   //
 
-  enyo.kind({
-    name: "XV.UnitRatio",
-    kind: "XV.Number",
-    scale: XT.UNIT_RATIO_SCALE
-  });
-
   enyo.kind({
     name: "XV.UnitRatioWidget",
     kind: "XV.NumberWidget",
@@ -188,12 +116,6 @@ regexp:true, undef:true, trailing:true, white:true */
   // WEIGHT
   //
 
-  enyo.kind({
-    name: "XV.Weight",
-    kind: "XV.Number",
-    scale: XT.WEIGHT_SCALE
-  });
-
   enyo.kind({
     name: "XV.WeightWidget",
     kind: "XV.NumberWidget",
index 5ffc5b4..48ca27a 100644 (file)
@@ -175,7 +175,8 @@ trailing:true, white:true, strict:false*/
       // see if toggle is on and update params
       _.each(keys, function (key) {
         _.each(actTypes[key], function (obj) {
-          if (that.$[_namify(obj)].getValue()) {
+          // the pluralize function in _namify is imperfect
+          if (that.$[_namify(obj)] && that.$[_namify(obj)].getValue()) {
             value.push(obj.type);
           }
         });
index a2e4a73..0ca32d7 100644 (file)
@@ -23,98 +23,49 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
     name: "XV.ContactWidget",
     kind: "XV.RelationWidget",
     label: "_contact".loc(),
-    collection: "XM.ContactRelationCollection",
-    list: "XV.ContactList",
     keyAttribute: "name",
     nameAttribute: "jobTitle",
     descripAttribute: "phone",
-    classes: "xv-relationwidget",
+    collection: "XM.ContactRelationCollection",
+    list: "XV.ContactList",
     published: {
       showAddress: false
     },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        {kind: "onyx.InputDecorator", name: "decorator",
-          classes: "xv-input-decorator", components: [
-          {name: "input", kind: "onyx.Input", classes: "xv-subinput",
-            onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
-            onfocus: "receiveFocus"
-          },
-          {kind: "onyx.MenuDecorator", onSelect: "itemSelected", components: [
-            {kind: "onyx.IconButton", classes: "icon-folder-open-alt"},
-            {name: "popupMenu", floating: true, kind: "onyx.Menu",
-              components: [
-              {kind: "XV.MenuItem", name: "searchItem", content: "_search".loc()},
-              {kind: "XV.MenuItem", name: "openItem", content: "_open".loc(),
-                disabled: true},
-              {kind: "XV.MenuItem", name: "newItem", content: "_new".loc(),
-                disabled: true}
-            ]}
-          ]},
-          {name: "completer", kind: "XV.Completer", onSelect: "itemSelected"}
-        ]}
+    descriptionComponents: [
+      {name: "jobTitleRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: 'xv-description', name: "name"}
+      ]},
+      {name: "phoneRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: "xv-description hyperlink", target: '_blank', name: "description"}
+      ]},
+      {name: "alternateRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: "xv-description hyperlink", target: "_blank", name: "alternate"}
       ]},
-      {kind: "FittableColumns", components: [
-        {name: "labels", classes: "xv-relationwidget-column left",
-          components: [
-          {name: "jobTitleLabel", content: "_jobTitle".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "phoneLabel", content: "_phone".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "alternateLabel", content: "_alternate".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "faxLabel", content: "_fax".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "primaryEmailLabel", content: "_email".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "webAddressLabel", content: "_web".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false},
-          {name: "addressLabel", content: "_address".loc() + ":",
-            classes: "xv-relationwidget-description label",
-            showing: false}
-        ]},
-        {name: "data", fit: true, components: [
-          {name: "name", classes: "xv-relationwidget-description hasLabel"},
-          {name: "description", ontap: "callPhone",
-            classes: "xv-relationwidget-description hasLabel hyperlink"},
-          {name: "alternate", classes: "xv-relationwidget-description hasLabel"},
-          {name: "fax", classes: "xv-relationwidget-description hasLabel"},
-          {name: "primaryEmail", ontap: "sendMail",
-            classes: "xv-relationwidget-description hasLabel hyperlink"},
-          {name: "webAddress", ontap: "openWindow",
-            classes: "xv-relationwidget-description hasLabel hyperlink"},
-          {name: "address", classes: "xv-relationwidget-description hasLabel",
-            allowHtml: true}
-        ]}
+      {name: "faxRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: "xv-description hyperlink", target: "_blank", name: "fax"}
+      ]},
+      {name: "emailRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: 'xv-description hyperlink', target: "_blank", name: "email"}
+      ]},
+      {name: "webAddressRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: 'xv-description hyperlink', target: "_blank", name: "webAddress"}
+      ]},
+      {name: "addressRow", controlClasses: "enyo-inline", showing: false, components: [
+        {classes: "xv-description", name: "address", allowHtml: true}
       ]}
     ],
-    disabledChanged: function () {
-      this.inherited(arguments);
-      var disabled = this.getDisabled();
-      if (this.$.phone) {
-        this.$.jobTitle.addRemoveClass("disabled", disabled);
-        this.$.phone.addRemoveClass("disabled", disabled);
-        this.$.alternate.addRemoveClass("disabled", disabled);
-        this.$.fax.addRemoveClass("disabled", disabled);
-        this.$.primaryEmail.addRemoveClass("disabled", disabled);
-        this.$.webAddress.addRemoveClass("disabled", disabled);
-      }
-    },
     setValue: function (value, options) {
       this.inherited(arguments);
+
       if (value && !value.get) {
         // the value of the widget is still being fetched asyncronously.
         // when the value is fetched, this function will be run again,
         // so for now we can just stop here.
         return;
       }
+
+      // The rows are here because sometimes the values needs labels
+      // to go with the values.
       var jobTitle = value ? value.get("jobTitle") : "",
         phone = value ? value.get("phone") : "",
         alternate = value ? value.get("alternate") : "",
@@ -123,23 +74,32 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
         webAddress = value ? value.get("webAddress") : "",
         address = value ? XM.Address.format(value.get("address")) : "",
         showAddress = this.getShowAddress();
-      this.$.jobTitleLabel.setShowing(jobTitle);
-      this.$.phoneLabel.setShowing(phone);
-      this.$.alternate.setShowing(alternate);
+
+      this.$.jobTitleRow.setShowing(!!jobTitle);
+      this.$.name.setContent(jobTitle);
+
+      this.$.phoneRow.setShowing(!!phone);
+      this.$.description.setContent(phone);
+      this.$.description.setAttribute('href', 'tel://' + phone);
+
+      this.$.alternateRow.setShowing(!!alternate);
       this.$.alternate.setContent(alternate);
-      this.$.alternateLabel.setShowing(alternate);
-      this.$.fax.setShowing(fax);
+      this.$.alternate.setAttribute('href', 'tel://' + alternate);
+
+      this.$.faxRow.setShowing(!!fax);
       this.$.fax.setContent(fax);
-      this.$.faxLabel.setShowing(fax);
-      this.$.primaryEmail.setShowing(primaryEmail);
-      this.$.primaryEmail.setContent(primaryEmail);
-      this.$.primaryEmailLabel.setShowing(primaryEmail);
-      this.$.webAddress.setShowing(webAddress);
+      this.$.fax.setAttribute('href', 'tel://' + fax);
+
+      this.$.emailRow.setShowing(!!primaryEmail);
+      this.$.email.setContent(primaryEmail);
+      this.$.email.setAttribute('href', 'mailto:' + primaryEmail);
+
+      this.$.webAddressRow.setShowing(!!webAddress);
       this.$.webAddress.setContent(webAddress);
-      this.$.webAddressLabel.setShowing(webAddress);
-      this.$.address.setShowing(address && showAddress);
-      this.$.addressLabel.setShowing(address && showAddress);
-      if (showAddress) { this.$.address.setContent(address); }
+      this.$.webAddress.setAttribute('href', '//' + alternate);
+
+      this.$.addressRow.setShowing(address && showAddress);
+      this.$.address.setContent(address);
     },
     openWindow: function () {
       var address = this.value ? this.value.get("webAddress") : null;
index ae86963..6c31ae2 100644 (file)
           "column": "cust_active"
         }
       },
+      {
+        "name": "customerType",
+        "toOne": {
+          "isNested": true,
+          "type": "CustomerType",
+          "column": "cust_custtype_id"
+        }
+      },
       {
         "name": "billingContact",
         "toOne": {
index d567c11..85a20d6 100644 (file)
@@ -38,7 +38,8 @@
         "name": "name",
         "attr": {
           "type": "String",
-          "column": "dept_name"
+          "column": "dept_name",
+          "required": true
         }
       }
     ],
@@ -83,7 +84,8 @@
         "name": "name",
         "attr": {
           "type": "String",
-          "column": "shift_name"
+          "column": "shift_name",
+          "required": true
         }
       }
     ],
index 8b1dca0..3ffb2f7 100644 (file)
@@ -31,7 +31,8 @@
         "attr": {
           "type": "String",
           "column": "warehous_code",
-          "isNaturalKey":true
+          "isNaturalKey":true,
+          "required": true
         }
       },
       {
@@ -39,7 +40,8 @@
         "toOne": {
           "isNested": true,
           "type": "SiteType",
-          "column": "warehous_sitetype_id"
+          "column": "warehous_sitetype_id",
+          "required": true
         }
       },
       {
           "column": "warehous_fob"
         }
       },
-      {
-        "name": "notes",
-        "attr": {
-          "type": "String",
-          "column": "warehous_shipcomments"
-        }
-      },
       {
         "name": "comments",
         "toMany": {
index 22e20d7..69b2d2c 100644 (file)
           "column": "grp_descrip"
         }
       },
+      {
+        "name": "grantedPrivileges",
+        "toMany": {
+          "type": "UserAccountRolePrivilegeAssignment",
+          "column": "grp_id",
+          "inverse": "userAccountRole",
+          "isNested": true
+        }
+      },
       {
         "name": "grantedExtensions",
         "toMany": {
     ],
     "isSystem": true
   },
+  {
+    "context": "xtuple",
+    "nameSpace": "SYS",
+    "type": "UserAccountRolePrivilegeAssignment",
+    "table": "grppriv",
+    "idSequenceName": "grppriv_grppriv_id_seq",
+    "comment": "User Account Role Privilege Assignment Map",
+    "privileges": {
+      "all": {
+        "create": true,
+        "read": true,
+        "update": false,
+        "delete": true
+      }
+    },
+    "properties": [
+      {
+        "name": "id",
+        "attr": {
+          "type": "Number",
+          "column": "grppriv_id",
+          "isPrimaryKey": true
+        }
+      },
+      {
+        "name": "uuid",
+        "attr": {
+          "type": "String",
+          "column": "obj_uuid",
+          "isNaturalKey": true
+        }
+      },
+      {
+        "name": "userAccountRole",
+        "attr": {
+          "type": "Number",
+          "column": "grppriv_grp_id"
+        }
+      },
+      {
+        "name": "privilege",
+        "toOne": {
+          "type": "Privilege",
+          "column": "grppriv_priv_id"
+        }
+      }
+    ],
+    "isNestedOnly": true,
+    "isSystem": true
+  },
   {
     "context": "xtuple",
     "nameSpace": "SYS",
index ce6663a..414c809 100644 (file)
@@ -5,6 +5,7 @@
     "type": "Url",
     "table": "urlinfo",
     "isRest": true,
+    "lockable": true,
     "idSequenceName": "urlinfo_url_id_seq",
     "comment": "URL Map",
     "privileges": {
diff --git a/enyo-client/database/source/add_admin_role.sql b/enyo-client/database/source/add_admin_role.sql
new file mode 100644 (file)
index 0000000..9f2f57d
--- /dev/null
@@ -0,0 +1,2 @@
+-- Add 'ADMIN' Role.
+select xt.add_role('ADMIN', 'Administrators Role');
diff --git a/enyo-client/database/source/grant_roles.sql b/enyo-client/database/source/grant_roles.sql
new file mode 100644 (file)
index 0000000..f164a8c
--- /dev/null
@@ -0,0 +1,2 @@
+-- Grant 'admin' user 'ADMIN' Role.
+select xt.grant_user_role('admin', 'ADMIN');
index 1f59a8b..57d0a90 100644 (file)
     "public/tables/vendaddrinfo.sql",
     "public/tables/wo.sql",
     "public/tables/womatl.sql",
+    "xt/functions/grant_role_priv.sql",
     "xt/functions/add_priv.sql",
+    "public/tables/priv.sql",
     "xt/functions/add_role.sql",
+    "add_admin_role.sql",
     "xt/functions/add_report_definition.sql",
     "xt/functions/average_cost.sql",
     "xt/functions/change_password.sql",
@@ -85,7 +88,6 @@
     "xt/functions/cntctrestore.sql",
     "xt/functions/createuser.sql",
     "xt/functions/cust_outstanding_credit.sql",
-    "xt/functions/grant_role_priv.sql",
     "xt/functions/grant_role_ext.sql",
     "xt/functions/grant_user_role.sql",
     "xt/functions/install_guiscript.sql",
     "public/tables/comment_trigger.sql",
     "public/tables/pkghead.sql",
     "public/tables/schemaord.sql",
-    "priv.sql",
+    "grant_roles.sql",
     "update_version.sql"
   ]
 }
diff --git a/enyo-client/database/source/populate_data.js b/enyo-client/database/source/populate_data.js
new file mode 100644 (file)
index 0000000..f7f23af
--- /dev/null
@@ -0,0 +1,3 @@
+exports.patches = [
+  {"nameSpace":"XM","type":"Customer","id":"TTOYS","patches":[{"op":"add","path":"/creditCards/0","value":{"isActive":true,"name":"John Brown","address1":"123 Test St","address2":"","city":"Norfolk","country":"United States","state":"VA","zip":"23517","creditCardType":"V","number":"4111111111111111","monthExpired":"12","yearExpired":"2020"}}],"binaryField":null,"requery":false,"encoding":"rjson"}
+];
diff --git a/enyo-client/database/source/priv.sql b/enyo-client/database/source/priv.sql
deleted file mode 100644 (file)
index 4c3e870..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
--- Setup default 'ADMIN' role and grant it to 'admin' user it it doesn't exist.
-
--- Add 'ADMIN' Role.
-select xt.add_role('ADMIN', 'Administrators Role');
-
--- Grant 'admin' user 'ADMIN' Role.
-select xt.grant_user_role('admin', 'ADMIN');
diff --git a/enyo-client/database/source/public/tables/priv.sql b/enyo-client/database/source/public/tables/priv.sql
new file mode 100644 (file)
index 0000000..0440815
--- /dev/null
@@ -0,0 +1 @@
+select xt.add_priv('InstallExtension', 'Can Install Extensions', 'command_center', 'CommandCenter');
index c137b5e..a23ed94 100644 (file)
@@ -1 +1 @@
-UPDATE pkghead SET pkghead_version = '4.5.0' WHERE pkghead_name = 'xt';
+UPDATE pkghead SET pkghead_version = '4.7.0Beta' WHERE pkghead_name = 'xt';
index dc75253..218222b 100644 (file)
@@ -32,8 +32,8 @@ select xt.install_js('XM','ItemSite','xtuple', $$
     @private
 
     This function supports the XM.ItemSiteListItem.fetch() and XM.ItemSiteRelation.fetch(),
-    but also xDruple extension XM.XdrupleCommerceProduct.xdCommerceProductFetch() call like this:
-    XM.ItemSitePrivate.fetch("XM.XdrupleCommerceProduct", "xdruple.xd_commerce_product", query, 'product_id', 'id');
+    but also xDruple extension XM.XdProduct.xdProductFetch() call like this:
+    XM.ItemSitePrivate.fetch("XM.XdProduct", "xdruple.xd_commerce_product", query, 'product_id', 'id');
   */
   XM.ItemSitePrivate.fetch = function (recordType, backingType, query, backingTypeJoinColumn, idColumn) {
     query = query || {};
index cd96e55..87037d2 100644 (file)
@@ -6,15 +6,18 @@ create or replace function xt.grant_role_priv(role_name text, priv_module text,
     sqlInsert = "insert into public.grppriv (grppriv_grp_id, grppriv_priv_id) values ($1, $2);",
     sqlRoleId = "select grp_id from public.grp where grp_name = $1;",
     sqlPrivId = "select priv_id from public.priv where priv_module = $1 and priv_name = $2;",
-    roleId = plv8.execute(sqlRoleId, [role_name.toUpperCase()])[0].grp_id,
-    privId = plv8.execute(sqlPrivId, [priv_module, priv_name])[0].priv_id,
+    roleId = plv8.execute(sqlRoleId, [role_name.toUpperCase()])[0],
+    privId = plv8.execute(sqlPrivId, [priv_module, priv_name])[0],
     count;
 
   if (!roleId || !privId) {
-    plv8.elog(WARNING, "Cannot grant Role: ", role_name, " Privilege: ", priv_name, ". The Role or Privilege has not been created yet.");
-
+    plv8.elog(WARNING, "Cannot grant Role: ", role_name, " Privilege: ", 
+      priv_name, ". The Role or Privilege has not been created yet.");
     return false;
+
   } else {
+    roleId = roleId.grp_id;
+    privId = privId.priv_id;
     count = plv8.execute(sqlCount, [roleId, privId])[0].count;
   }
 
index c972418..d438be2 100644 (file)
@@ -48,7 +48,6 @@ insert into itemsite (
   itemsite_location_comments,
   itemsite_notes,
   itemsite_perishable,
-  itemsite_nnqoh,
   itemsite_autoabcclass,
   itemsite_ordergroup,
   itemsite_disallowblankwip,
@@ -109,7 +108,6 @@ insert into itemsite (
   new.itemsite_location_comments,
   new.itemsite_notes,
   coalesce(new.itemsite_perishable, false),
-  0,
   coalesce(new.itemsite_autoabcclass, false),
   coalesce(new.itemsite_ordergroup, 1),
   coalesce(new.itemsite_disallowblankwip, false),
index 70fc13a..d8078ce 100644 (file)
@@ -7,10 +7,7 @@ white:true*/
   "use strict";
 
   XT.extensions.billing = {
-    name: "billing",
-    setVersion: function () {
-      XT.setVersion("", XT.extensions.billing.name);
-    }
+    name: "billing"
   };
 
 }());
index 2691507..b1489bf 100644 (file)
@@ -6,10 +6,6 @@ white:true*/
 (function () {
   "use strict";
 
-  XT.extensions.crm = {
-    setVersion: function () {
-      XT.setVersion("", "crm");
-    }
-  };
+  XT.extensions.crm = {};
 
 }());
index f204ccf..af3ceee 100644 (file)
@@ -15,7 +15,6 @@ strict:true, trailing:true, white:true */
     "_incidentStatusColors": "Incident Status Colors",
     "_opportunitiesNext30Days": "Opportunities Next 30 Days",
     "_maintainEmailProfiles": "Maintain Email Profiles",
-    "_staleAnalysisWarning": "Free trial demo analysis data will not be updated from your live changes.",
     "_viewEmailProfiles": "View Email Profiles"
   });
 
index 78d5771..2a57a3c 100644 (file)
@@ -81,11 +81,6 @@ trailing:true, white:true*/
       XT.app.$.postbooks.insertModule(dashboardModule, 0);
     }
 
-    isBiAvailable = XT.session.config.biAvailable && XT.session.privileges.get("ViewSalesHistory");
-    if (isBiAvailable) {
-      module.panels.push({name: "analysisPage", kind: "analysisFrame"});
-    }
-
     XT.app.$.postbooks.insertModule(module, 0);
 
     relevantPrivileges = [
@@ -151,54 +146,5 @@ trailing:true, white:true*/
     ];
     XT.session.addRelevantPrivileges(module.name, relevantPrivileges);
 
-    /**
-      This iFrame is to show the Analysis tool.
-      On creation, it uses the analysis route to generate a signed,
-      encoded JWT which it sends to Pentaho to get the report.
-    */
-    enyo.kind({
-      name: "analysisFrame",
-      label: "_analysis".loc(),
-      tag: "iframe",
-      style: "border: none;",
-      attributes: {src: ""},
-      events: {
-        onMessage: ""
-      },
-      published: {
-        source: ""
-      },
-
-      create: function () {
-        this.inherited(arguments);
-        if (XT.session.config.freeDemo) {
-          this.doMessage({message: "_staleAnalysisWarning".loc()});
-        }
-        // generate the web token and render
-        // the iFrame
-        var url, ajax = new enyo.Ajax({
-          url: XT.getOrganizationPath() + "/analysis",
-          handleAs: "text"
-        });
-        ajax.response(this, function (inSender, inResponse) {
-          this.setSource(inResponse);
-        });
-        // uh oh. HTTP error
-        ajax.error(this, function (inSender, inResponse) {
-          // TODO: trigger some kind of error here
-          console.log("There was a problem generating the iFrame");
-        });
-        // param for the report name
-        ajax.go({reportUrl: "content/saiku-ui/index.html?biplugin=true"});
-      },
-      /**
-        When the published source value is set, this sets the src
-        attribute on the iFrame.
-      */
-      sourceChanged: function () {
-        this.inherited(arguments);
-        this.setAttributes({src: this.getSource()});
-      }
-    });
   };
 }());
index 016dae7..4b2a940 100644 (file)
@@ -51,11 +51,11 @@ trailing:true, white:true*/
         parameters: [{
           attribute: "targetClose",
           operator: ">=",
-          value: XT.date.applyTimezoneOffset(XV.Date.prototype.textToDate("0"), true)
+          value: XT.date.applyTimezoneOffset(XV.DateWidget.prototype.textToDate("0"), true)
         }, {
           attribute: "targetClose",
           operator: "<=",
-          value: XT.date.applyTimezoneOffset(XV.Date.prototype.textToDate("+30"), true)
+          value: XT.date.applyTimezoneOffset(XV.DateWidget.prototype.textToDate("+30"), true)
         }]
       },
       totalField: "amount"
index 50c6ad1..17bb596 100644 (file)
@@ -6,10 +6,6 @@ white:true*/
 (function () {
   "use strict";
 
-  XT.extensions.oauth2 = {
-    setVersion: function () {
-      XT.setVersion("4.4.0", "oauth2");
-    }
-  };
+  XT.extensions.oauth2 = {};
 
 }());
index f34b602..56c2a22 100644 (file)
@@ -17,9 +17,8 @@ strict:true, trailing:true, white:true */
     "_issued": "Issued",
     "_fullListUrl": "Full List URL",
     "_generatingPrivateKey": "A new keypair will be generated for this OAUTH2 client. " +
-      "The public key will be saved in the database with this client. The private key " +
-      "is available as a one-time download. The password for the key store file will be " +
-      "\"notasecret\". Click \"ok\" to downloading the private key.",
+      "The public key will be available in the future with this client. The private key " +
+      "is only available now as a one-time download.",
     "_logoURL": "Logo URL",
     "_maintainOauth2clients": "Maintain OAUTH2 Clients",
     "_oauth2": "OAUTH2",
index 20f968a..5afc2df 100644 (file)
@@ -34,6 +34,7 @@ white:true*/
       bindEvents: function () {
         XM.Model.prototype.bindEvents.apply(this, arguments);
         this.on('statusChange', this.statusDidChange);
+        this.on('change:clientType', this.clientTypeDidChange);
       },
 
       // clientType must not be editable once first saved.
@@ -51,6 +52,10 @@ white:true*/
         }
       },
 
+      clientTypeDidChange: function () {
+        this.set("delegatedAccess", this.get("clientType") === 'jwt bearer');
+      },
+
       save: function (key, value, options) {
         // Handle both `"key", value` and `{key: value}` -style arguments.
         if (_.isObject(key) || _.isEmpty(key)) {
index 9e18f0d..fe60f97 100644 (file)
@@ -32,7 +32,8 @@ white:true*/
               {kind: "XV.DateWidget", attr: "issued"},
               {kind: "XV.InputWidget", attr: "organization"},
               {kind: "XV.CheckboxWidget", name: "delegatedAccess", attr: "delegatedAccess"},
-              {kind: "XV.InputWidget", name: "clientX509PubCert", attr: "clientX509PubCert", label: "_x509PubCert".loc()},
+              {kind: "onyx.GroupboxHeader", content: "_x509PubCert".loc()},
+              {kind: "XV.TextArea", name: "clientX509PubCert", attr: "clientX509PubCert"},
               {kind: "onyx.GroupboxHeader", content: "_fullListUrl".loc()},
               {kind: "XV.TextArea", name: "fullListUrl", classes: "xv-short-textarea", disabled: true},
               {kind: "onyx.GroupboxHeader", content: "_singleResourceUrl".loc()},
@@ -45,7 +46,7 @@ white:true*/
               {kind: "XV.TextArea", name: "tokenRevocationURI", classes: "xv-short-textarea", disabled: true}
             ]}
           ]},
-          {kind: "XV.Oauth2clientRedirectBox", name: "redirectBox", attr: "redirectURIs" }
+          {kind: "XV.Oauth2clientRedirectBox", name: "redirectBox", attr: "redirectURIs", showing: false}
         ]}
       ],
       create: function () {
@@ -61,15 +62,15 @@ white:true*/
       attributesChanged: function (model, options) {
         this.inherited(arguments);
 
-        this.$.delegatedAccess.setShowing(model.get("clientType") === 'jwt bearer');
-        this.$.clientX509PubCert.setShowing(model.get("clientType") === 'jwt bearer');
-        // Enyo messes this one up for some reason, so use CSS
-        if (model.get("clientType") === 'web server') {
-          this.$.redirectBox.applyStyle("visibility", "showing");
-        } else {
-          this.$.redirectBox.applyStyle("visibility", "hidden");
-        }
+        var serviceAccount = model.get("clientType") === 'jwt bearer',
+          webServer = model.get("clientType") === 'web server';
 
+        // Delegated Access is only meaningful for Service Accounts
+        this.$.delegatedAccess.setShowing(serviceAccount);
+        this.$.clientX509PubCert.setShowing(serviceAccount);
+        this.$.redirectBox.setShowing(webServer);
+        // There is some rendering issue with this box that this fixes w/o css
+        this.$.redirectBox.render();
       }
     });
 
index 7124aff..a967d4c 100644 (file)
@@ -6,10 +6,6 @@ white:true*/
 (function () {
   "use strict";
 
-  XT.extensions.project = {
-    setVersion: function () {
-      XT.setVersion("", "project");
-    }
-  };
+  XT.extensions.project = {};
 
 }());
index d7ec1e8..d88578a 100644 (file)
@@ -6,10 +6,6 @@ white:true*/
 (function () {
   "use strict";
 
-  XT.extensions.purchasing = {
-    setVersion: function () {
-      XT.setVersion("", "purchasing");
-    }
-  };
+  XT.extensions.purchasing = {};
 
 }());
index fa285e8..0868e86 100644 (file)
@@ -57,6 +57,7 @@ strict:true, trailing:true, white:true */
     "_UseEarliestAvailDateOnPOItem": "Use Earliest Date",
     "_vendorItem": "Vendor Item",
     "_vendorItemNumber": "VendorItemNumber",
+    "_vendors": "Vendors",
     "_vendorUnit": "Vendor Unit",
     "_viewPurchaseOrders": "View Purchase Orders",
     "_vouchered": "Vouchered",
index 780df0d..dca6a6b 100644 (file)
@@ -31,71 +31,32 @@ white:true, strict:false*/
         showDetail: true,
         vendorItemNumber: null,
       },
-      components: [
-        {kind: "FittableColumns", components: [
-          {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-          {kind: "onyx.InputDecorator", name: "decorator",
-            classes: "xv-input-decorator", components: [
-            {name: "input", kind: "onyx.Input", classes: "xv-subinput",
-              onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
-              onfocus: "receiveFocus"
-            },
-            {kind: "onyx.MenuDecorator", onSelect: "itemSelected", components: [
-              {kind: "onyx.IconButton", classes: "icon-folder-open-alt"},
-              {name: "popupMenu", floating: true, kind: "onyx.Menu",
-                components: [
-                {kind: "XV.MenuItem", name: "searchItem", content: "_search".loc()},
-                {kind: "XV.MenuItem", name: "openItem", content: "_open".loc(),
-                  disabled: true},
-                {kind: "XV.MenuItem", name: "newItem", content: "_new".loc(),
-                  disabled: true}
-              ]}
-            ]},
-            {name: "completer", kind: "XV.Completer", onSelect: "itemSelected"}
-          ]}
-        ]},
-        {kind: "FittableColumns", name: "detailColumns", components: [
-          {name: "labels", classes: "xv-relationwidget-column left",
-            components: [
-            {name: "contractLabel", content: "_contract".loc() + ":",
-              classes: "xv-relationwidget-description label",
-              showing: false},
-            {name: "minimumQtyLabel", content: "_minimumOrderQuantity".loc() + ":",
-              classes: "xv-relationwidget-description label",
-              showing: false},
-            {name: "multipleQtyLabel", content: "_multipleOrderQuantity".loc() + ":",
-              classes: "xv-relationwidget-description label",
-              showing: false},
-            {name: "earliestDateLabel", content: "_earliestDate".loc() + ":",
-              classes: "xv-relationwidget-description label",
-              showing: false}
+      descriptionComponents: [
+        {controlClasses: 'enyo-inline', components: [
+          {name: "nameRow", controlClasses: "enyo-inline", components: [
+            {name: "name", classes: "xv-description"}
+          ]},
+          {name: "contractRow", controlClasses: "enyo-inline", components: [
+            {classes: 'xv-label', content: "_contract".loc() + ":"},
+            {name: "description", classes: "xv-description"}
+          ]},
+          {name: "minimumQtyRow", controlClasses: "enyo-inline", components: [
+            {classes: 'xv-label', content: "_minimumOrderQuantity".loc() + ":"},
+            {name: "minimumQty", classes: "xv-description"}
           ]},
-          {name: "data", fit: true, components: [
-            {name: "name", classes: "xv-relationwidget-description hasLabel",
-              showing: false},
-            {name: "description", classes: "xv-relationwidget-description hasLabel",
-              showing: false},
-            {name: "minimumQty", classes: "xv-relationwidget-description hasLabel",
-              showing: false},
-            {name: "multipleQty", classes: "xv-relationwidget-description hasLabel",
-              showing: false},
-            {name: "earliestDate", classes: "xv-relationwidget-description hasLabel",
-              showing: false}
+          {name: "multipleQtyRow", controlClasses: "enyo-inline", components: [
+            {classes: 'xv-label', content: "_multipleOrderQuantity".loc() + ":"},
+            {name: "multipleQty", classes: "xv-description"}
+          ]},
+          {name: "earliestDateRow", controlClasses: "enyo-inline", components: [
+            {classes: 'xv-label', content: "_earliestDate".loc() + ":"},
+            {name: "earliestDate", classes: "xv-description"}
           ]}
         ]}
       ],
       create: function () {
         this.inherited(arguments);
-        if (!this.getShowDetail()) {
-          this.$.detailColumns.setStyle("display: none");
-        }
-      },
-      disabledChanged: function () {
-        this.inherited(arguments);
-        var disabled = this.getDisabled();
-        this.$.minimumQty.addRemoveClass("disabled", disabled);
-        this.$.multipleQty.addRemoveClass("disabled", disabled);
-        this.$.earliestDate.addRemoveClass("disabled", disabled);
+        this.$.descriptionContainer.setShowing(this.getShowDetail());
       },
       /**
         Can accept a two property object with an item source and vendor item number
@@ -176,9 +137,10 @@ white:true, strict:false*/
 
         // Handle menu actions
         that.$.openItem.setShowing(true);
-        that.$.newItem.setShowing(true);
         that.$.openItem.setDisabled(true);
+        that.$.newItem.setShowing(true);
         that.$.newItem.setDisabled(_couldNotCreate.apply(this) || this.disabled);
+
         if (Model) { setPrivileges(); }
 
         if (this.getShowDetail()) {
@@ -187,15 +149,17 @@ white:true, strict:false*/
             multipleQty = value ? value.get("multipleOrderQuantity") : 0,
             earliestDate = value ? XT.date.applyTimezoneOffset(value.get("earliestDate"), true) : null,
             scale = XT.QTY_SCALE;
-          this.$.contractLabel.setShowing(contract);
-          this.$.minimumQtyLabel.setShowing(minimumQty);
-          this.$.minimumQty.setShowing(minimumQty);
+
+          this.$.contractRow.setShowing(!!contract);
+          this.$.description.setContent(contract);
+
+          this.$.minimumQtyRow.setShowing(!!minimumQty);
           this.$.minimumQty.setContent(Globalize.format(minimumQty, "n" + scale));
-          this.$.multipleQtyLabel.setShowing(multipleQty);
-          this.$.multipleQty.setShowing(multipleQty);
+
+          this.$.multipleQtyRow.setShowing(!!multipleQty);
           this.$.multipleQty.setContent(Globalize.format(multipleQty, "n" + scale));
-          this.$.earliestDateLabel.setShowing(earliestDate);
-          this.$.earliestDate.setShowing(earliestDate);
+
+          this.$.earliestDateRow.setShowing(!!earliestDate);
           this.$.earliestDate.setContent(Globalize.format(earliestDate, "d"));
         }
       },
index 40bbfd6..0ea1d73 100644 (file)
@@ -6,10 +6,6 @@ white:true*/
 (function () {
   "use strict";
 
-  XT.extensions.sales = {
-    setVersion: function () {
-      XT.setVersion("", "sales");
-    }
-  };
+  XT.extensions.sales = {};
 
 }());
index bf6ef81..4a7506f 100644 (file)
@@ -65,7 +65,6 @@ strict:true, trailing:true, white:true */
     "_shipTo": "Ship To",
     "_showQuotesAfterConverted": "Show Quotes after Conversion to SO",
     "_showSaveAndAddbutton": "Show 'Save and Add to Packing List' Button on Sales Order",
-    "_staleAnalysisWarning": "Free trial demo analysis data will not be updated from your live changes.",
     "_termsType": "Terms Type",
     "_thisWeek": "This Week",
     "_thisMonth": "This Month",
index 583fe69..97250d3 100644 (file)
@@ -98,11 +98,6 @@ trailing:true, white:true*/
       }
     }
 
-    isBiAvailable = XT.session.config.biAvailable && XT.session.privileges.get("ViewSalesHistory");
-    if (isBiAvailable) {
-      module.panels.push({name: "salesAnalysisPage", kind: "analysisFrame"});
-    }
-
     XT.app.$.postbooks.insertModule(module, 0);
 
     relevantPrivileges = [
@@ -175,54 +170,5 @@ trailing:true, white:true*/
     ];
     XT.session.addRelevantPrivileges(module.name, relevantPrivileges);
 
-    /**
-      This iFrame is to show the Sales Analysis report from Pentaho.
-      On creation, it uses the analysis route to generate a signed,
-      encoded JWT which it sends to Pentaho to get the report.
-    */
-    enyo.kind({
-      name: "analysisFrame",
-      label: "_analysis".loc(),
-      tag: "iframe",
-      style: "border: none;",
-      attributes: {src: ""},
-      events: {
-        onMessage: ""
-      },
-      published: {
-        source: ""
-      },
-
-      create: function () {
-        this.inherited(arguments);
-        if (XT.session.config.freeDemo) {
-          this.doMessage({message: "_staleAnalysisWarning".loc()});
-        }
-        // generate the web token and render
-        // the iFrame
-        var url, ajax = new enyo.Ajax({
-          url: XT.getOrganizationPath() + "/analysis",
-          handleAs: "text"
-        });
-        ajax.response(this, function (inSender, inResponse) {
-          this.setSource(inResponse);
-        });
-        // uh oh. HTTP error
-        ajax.error(this, function (inSender, inResponse) {
-          // TODO: trigger some kind of error here
-          console.log("There was a problem generating the iFrame");
-        });
-        // param for the report name
-        ajax.go({reportUrl: "content/saiku-ui/index.html?biplugin=true"});
-      },
-      /**
-        When the published source value is set, this sets the src
-        attribute on the iFrame.
-      */
-      sourceChanged: function () {
-        this.inherited(arguments);
-        this.setAttributes({src: this.getSource()});
-      }
-    });
   };
 }());
index 266314d..bdae9cd 100644 (file)
@@ -170,7 +170,7 @@ trailing:true, white:true*/
       {kind: "XV.MoneyWidget",
         attr: {localValue: "authorizedCredit", currency: "currency"},
         label: "_authorizedCredit".loc(), currencyShowing: false,
-        container: "invoiceLineItemBox.summaryPanel.summaryColumnOne",
+        container: "lineItemBox.summaryPanel.summaryColumnOne",
         defer: true},
       {kind: "XV.InputWidget", container: "mainSubgroup", addBefore: "isPosted",
         attr: "orderNumber"},
index 6180e9e..ed2035d 100644 (file)
@@ -19,7 +19,7 @@ trailing:true, white:true*/
       parameters: [{
         attribute: "shipDate",
         operator: ">=",
-        value: XT.date.applyTimezoneOffset(XV.Date.prototype.textToDate("-30"), true)
+        value: XT.date.applyTimezoneOffset(XV.DateWidget.prototype.textToDate("-30"), true)
       }]
     },
     dateField: "shipDate",
@@ -40,11 +40,11 @@ trailing:true, white:true*/
       parameters: [{
         attribute: "orderDate",
         operator: ">=",
-        value: XT.date.applyTimezoneOffset(XV.Date.prototype.textToDate("0"), true)
+        value: XT.date.applyTimezoneOffset(XV.DateWidget.prototype.textToDate("0"), true)
       }, {
         attribute: "orderDate",
         operator: "<=",
-        value: XT.date.applyTimezoneOffset(XV.Date.prototype.textToDate("+30"), true)
+        value: XT.date.applyTimezoneOffset(XV.DateWidget.prototype.textToDate("+30"), true)
       }]
     },
     dateField: "orderDate",
index 35330d2..dcda6af 100644 (file)
@@ -7,11 +7,14 @@
   "databaseScripts": [
     "../lib/orm/source/create_xt_schema.sql",
     "../lib/orm/source/xt/functions/add_column.sql",
+    "../lib/orm/source/xt/functions/add_comment_type.sql",
     "../lib/orm/source/xt/functions/add_constraint.sql",
     "../lib/orm/source/xt/functions/add_index.sql",
     "../lib/orm/source/xt/functions/add_primary_key.sql",
     "../lib/orm/source/xt/functions/create_table.sql",
 
+    "public/patches/fixflcol.sql",
+
     "public/indexes/apopentax.sql",
     "public/indexes/aropentax.sql",
     "public/indexes/asohisttax.sql",
@@ -81,6 +84,7 @@
     "public/functions/averagesalesprice.sql",
     "public/functions/avgcost.sql",
     "public/functions/balanceitemsite.sql",
+    "public/functions/bankreconciliation.sql",
     "public/functions/basecurrid.sql",
     "public/functions/bomcontains.sql",
     "public/functions/bomhistsequence.sql",
     "public/functions/haspriv.sql",
     "public/functions/hasprivonobject.sql",
     "public/functions/implodewo.sql",
+    "public/functions/importbankreccleared.sql",
     "public/functions/incdt.sql",
     "public/functions/indentedbom.sql",
     "public/functions/indentedwhereused.sql",
     "public/functions/purgepostedcounttags.sql",
     "public/functions/purgeshipments.sql",
     "public/functions/qtyallocated.sql",
+    "public/functions/qtyatlocation.sql",
     "public/functions/qtyatshipping.sql",
     "public/functions/qtyavailable.sql",
     "public/functions/qtyinshipment.sql",
     "public/functions/qtylocation.sql",
+    "public/functions/qtynetable.sql",
     "public/functions/qtyordered.sql",
     "public/functions/qtypr.sql",
     "public/functions/qtyreserved.sql",
     "public/functions/releaseinvcnumber.sql",
     "public/functions/releasenumber.sql",
     "public/functions/releaseponumber.sql",
+    "public/functions/releasepr.sql",
     "public/functions/releaseprnumber.sql",
     "public/functions/releasepurchaseorder.sql",
     "public/functions/releasequnumber.sql",
     "public/functions/transtype.sql",
     "public/functions/trylock.sql",
     "public/functions/undomerge.sql",
+    "public/functions/unreleasepurchaseorder.sql",
     "public/functions/uomusedforitem.sql",
     "public/functions/updateabcclass.sql",
     "public/functions/updatecharassignment.sql",
     "public/trigger_functions/wo.sql",
     "public/trigger_functions/womatl.sql",
 
+    "public/tables/bankrecimport.sql",
     "public/tables/bankrecitem.sql",
     "public/tables/cashrcpt.sql",
     "public/tables/ccpay.sql",
+    "public/tables/ccbank.sql",
+    "public/tables/checkhead.sql",
+    "public/tables/itemsite.sql",
+    "public/tables/location.sql",
     "public/tables/metric.sql",
     "public/tables/payco.sql",
     "public/tables/priv.sql",
     "public/tables/tax.sql",
     "public/tables/taxpay.sql",
 
-    "public/tables/location.sql",
     "public/views/address.sql",
     "public/views/apmemo.sql",
     "public/views/armemo.sql",
     "public/tables/report/items.xml",
 
     "public/patches/fixacl.sql",
-    "public/patches/populate_ccpay_card_type.sql"
+    "public/patches/populate_ccpay_card_type.sql",
+
+    "public/tables/setVersion.sql"
   ]
 }
index b7ece97..a076ade 100644 (file)
@@ -10429,22 +10429,6 @@ ALTER TABLE cashrcptmisc ENABLE TRIGGER ALL;
 SELECT pg_catalog.setval('cashrcptmisc_cashrcptmisc_id_seq', 28, true);
 
 
---
--- TOC entry 8951 (class 0 OID 146567491)
--- Dependencies: 278 8914 9465
--- Data for Name: ccard; Type: TABLE DATA; Schema: public; Owner: admin
---
-
-ALTER TABLE ccard DISABLE TRIGGER ALL;
-
-INSERT INTO ccard (ccard_id, ccard_seq, ccard_cust_id, ccard_active, ccard_name, ccard_address1, ccard_address2, ccard_city, ccard_state, ccard_zip, ccard_country, ccard_number, ccard_debit, ccard_month_expired, ccard_year_expired, ccard_type, ccard_date_added, ccard_lastupdated, ccard_added_by_username, ccard_last_updated_by_username) VALUES (5, 10, 95, false, '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, '\x5a45c679e17cc639', '\xeccde4115b93a677', 'V', '2005-12-28 12:38:34.255053', '2006-01-13 11:01:08.290173', 'jsmith', 'jsmith');
-INSERT INTO ccard (ccard_id, ccard_seq, ccard_cust_id, ccard_active, ccard_name, ccard_address1, ccard_address2, ccard_city, ccard_state, ccard_zip, ccard_country, ccard_number, ccard_debit, ccard_month_expired, ccard_year_expired, ccard_type, ccard_date_added, ccard_lastupdated, ccard_added_by_username, ccard_last_updated_by_username) VALUES (6, 20, 95, false, '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, '\x5a45c679e17cc639', '\xd73802f77991ebf3', 'V', '2005-12-28 15:00:24.567592', '2008-06-12 16:33:35.455292', 'jsmith', 'jsmith');
-INSERT INTO ccard (ccard_id, ccard_seq, ccard_cust_id, ccard_active, ccard_name, ccard_address1, ccard_address2, ccard_city, ccard_state, ccard_zip, ccard_country, ccard_number, ccard_debit, ccard_month_expired, ccard_year_expired, ccard_type, ccard_date_added, ccard_lastupdated, ccard_added_by_username, ccard_last_updated_by_username) VALUES (7, 30, 95, true, '\x4e8dd44d5c61dd0636233ffe3f9e82c4', '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', '\x67cea78a35d2bf07042b2bf2b936c257', '\x0c80174edff323088009d8831363b1d2', '\x329e5c640fc98253', '\xb20defeef11e27bf', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, '\x5a45c679e17cc639', '\x8f76d50339514e01', 'V', '2008-06-12 16:33:55.904522', '2008-06-12 16:33:55.904522', 'jsmith', 'jsmith');
-INSERT INTO ccard (ccard_id, ccard_seq, ccard_cust_id, ccard_active, ccard_name, ccard_address1, ccard_address2, ccard_city, ccard_state, ccard_zip, ccard_country, ccard_number, ccard_debit, ccard_month_expired, ccard_year_expired, ccard_type, ccard_date_added, ccard_lastupdated, ccard_added_by_username, ccard_last_updated_by_username) VALUES (8, 40, 95, true, '\xf7467e1ac14b6951efe53b88e40ae0b2', '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', '\x67cea78a35d2bf07042b2bf2b936c257', '\x0c80174edff323088009d8831363b1d2', '\x329e5c640fc98253', '\xb20defeef11e27bf', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, '\x717c001aca9d6acb', '\xd73802f77991ebf3', 'V', '2008-10-02 09:03:48.93983', '2008-10-02 09:11:20.569342', 'jsmith', 'jsmith');
-
-
-ALTER TABLE ccard ENABLE TRIGGER ALL;
-
 --
 -- TOC entry 9500 (class 0 OID 0)
 -- Dependencies: 481
@@ -10454,38 +10438,6 @@ ALTER TABLE ccard ENABLE TRIGGER ALL;
 SELECT pg_catalog.setval('ccard_ccard_id_seq', 8, true);
 
 
---
--- TOC entry 9082 (class 0 OID 146568608)
--- Dependencies: 482 9465
--- Data for Name: ccardaud; Type: TABLE DATA; Schema: public; Owner: admin
---
-
-ALTER TABLE ccardaud DISABLE TRIGGER ALL;
-
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (1, 5, NULL, 10, NULL, 95, NULL, true, NULL, '\x6cbaa91473e4d26a', NULL, '\x4a3370cfda233487', NULL, '\x6d09a44bdb032972', NULL, '\x8e628c8e22757f48', NULL, '\x606a62a88441ccce', NULL, '\x558f7444709895a1', NULL, '\xdf87001e7930c20fc49ba45b4abec021', NULL, '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', NULL, false, NULL, '\x5a45c679e17cc639', NULL, '\xeccde4115b93a677', NULL, 'V', '2005-12-28 12:38:34.255053', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (2, 5, 10, 10, 95, 95, true, true, '\x6cbaa91473e4d26a', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x606a62a88441ccce', '\x558f7444709895a1', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2005-12-28 12:40:36.077514', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (3, 5, 10, 10, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x606a62a88441ccce', '\x558f7444709895a1', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2005-12-28 12:42:20.793589', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (4, 5, 10, 10, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x606a62a88441ccce', '\x558f7444709895a1', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2005-12-28 12:45:47.388653', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (5, 5, 10, 10, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x606a62a88441ccce', '\x558f7444709895a1', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2005-12-28 12:50:46.680185', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (6, 6, NULL, 20, NULL, 95, NULL, true, NULL, '\xa193fa22e7139e08744e2b086ab9bbf6', NULL, '\x0c2c4cb15a0492bb7749eda5c22a70b7', NULL, '\x2be9b3f00610c5fd', NULL, '\x79102906ee72e12b9aeee62e181d5fb1', NULL, '\x329e5c640fc98253', NULL, '\x51200a4f8d21e527', NULL, '\xdf87001e7930c20fc49ba45b4abec021', NULL, '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', NULL, false, NULL, '\x5a45c679e17cc639', NULL, '\xeccde4115b93a677', NULL, 'V', '2005-12-28 15:00:24.567592', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (7, 6, 20, 20, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x2be9b3f00610c5fd', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2005-12-28 15:01:17.664311', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (8, 5, 10, 10, 95, 95, true, false, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x4a3370cfda233487', '\x4a3370cfda233487', '\x6d09a44bdb032972', '\x6d09a44bdb032972', '\x8e628c8e22757f48', '\x8e628c8e22757f48', '\x606a62a88441ccce', '\x606a62a88441ccce', '\x558f7444709895a1', '\x558f7444709895a1', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2006-01-13 11:01:08.290173', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (9, 6, 20, 20, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2006-01-13 11:01:30.327048', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (10, 6, 20, 20, 95, 95, true, false, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xeccde4115b93a677', 'V', 'V', '2008-03-04 13:55:01.303273', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (11, 6, 20, 20, 95, 95, false, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xeccde4115b93a677', '\xd73802f77991ebf3', 'V', 'V', '2008-06-12 15:58:13.904141', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (12, 6, 20, 20, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xd73802f77991ebf3', '\xd73802f77991ebf3', 'V', 'V', '2008-06-12 16:16:50.490189', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (13, 6, 20, 20, 95, 95, true, true, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xd73802f77991ebf3', '\xd73802f77991ebf3', 'V', 'V', '2008-06-12 16:16:50.590829', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (14, 6, 20, 20, 95, 95, true, false, '\xa193fa22e7139e08744e2b086ab9bbf6', '\xa193fa22e7139e08744e2b086ab9bbf6', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x0c2c4cb15a0492bb7749eda5c22a70b7', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x79102906ee72e12b9aeee62e181d5fb1', '\x329e5c640fc98253', '\x329e5c640fc98253', '\x51200a4f8d21e527', '\x51200a4f8d21e527', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x5a45c679e17cc639', '\x5a45c679e17cc639', '\xd73802f77991ebf3', '\xd73802f77991ebf3', 'V', 'V', '2008-06-12 16:33:35.455292', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (15, 7, NULL, 30, NULL, 95, NULL, true, NULL, '\x4e8dd44d5c61dd0636233ffe3f9e82c4', NULL, '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', NULL, '\x67cea78a35d2bf07042b2bf2b936c257', NULL, '\x0c80174edff323088009d8831363b1d2', NULL, '\x329e5c640fc98253', NULL, '\xb20defeef11e27bf', NULL, '\xdf87001e7930c20fc49ba45b4abec021', NULL, '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', NULL, false, NULL, '\x5a45c679e17cc639', NULL, '\x8f76d50339514e01', NULL, 'V', '2008-06-12 16:33:55.904522', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (16, 8, NULL, 40, NULL, 95, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, NULL, 'V', '2008-10-02 09:03:48.93983', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (17, 8, 40, 40, 95, 95, true, true, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, NULL, NULL, NULL, NULL, 'V', 'V', '2008-10-02 09:06:42.921758', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (18, 8, 40, 40, 95, 95, true, true, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, NULL, NULL, NULL, NULL, 'V', 'V', '2008-10-02 09:06:42.955925', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (19, 8, 40, 40, 95, 95, true, true, NULL, '\xf7467e1ac14b6951efe53b88e40ae0b2', NULL, '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', NULL, '\x67cea78a35d2bf07042b2bf2b936c257', NULL, '\x0c80174edff323088009d8831363b1d2', NULL, '\x329e5c640fc98253', NULL, '\xb20defeef11e27bf', NULL, '\xdf87001e7930c20fc49ba45b4abec021', NULL, NULL, false, false, NULL, '\x717c001aca9d6acb', NULL, '\xd73802f77991ebf3', 'V', 'V', '2008-10-02 09:11:20.508258', 'jsmith');
-INSERT INTO ccardaud (ccardaud_id, ccardaud_ccard_id, ccardaud_ccard_seq_old, ccardaud_ccard_seq_new, ccardaud_ccard_cust_id_old, ccardaud_ccard_cust_id_new, ccardaud_ccard_active_old, ccardaud_ccard_active_new, ccardaud_ccard_name_old, ccardaud_ccard_name_new, ccardaud_ccard_address1_old, ccardaud_ccard_address1_new, ccardaud_ccard_address2_old, ccardaud_ccard_address2_new, ccardaud_ccard_city_old, ccardaud_ccard_city_new, ccardaud_ccard_state_old, ccardaud_ccard_state_new, ccardaud_ccard_zip_old, ccardaud_ccard_zip_new, ccardaud_ccard_country_old, ccardaud_ccard_country_new, ccardaud_ccard_number_old, ccardaud_ccard_number_new, ccardaud_ccard_debit_old, ccardaud_ccard_debit_new, ccardaud_ccard_month_expired_old, ccardaud_ccard_month_expired_new, ccardaud_ccard_year_expired_old, ccardaud_ccard_year_expired_new, ccardaud_ccard_type_old, ccardaud_ccard_type_new, ccardaud_ccard_last_updated, ccardaud_ccard_last_updated_by_username) VALUES (20, 8, 40, 40, 95, 95, true, true, '\xf7467e1ac14b6951efe53b88e40ae0b2', '\xf7467e1ac14b6951efe53b88e40ae0b2', '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', '\x9bae90ed2d4a7aadbd8fcc9801cc9c0991852a6a04744731', '\x67cea78a35d2bf07042b2bf2b936c257', '\x67cea78a35d2bf07042b2bf2b936c257', '\x0c80174edff323088009d8831363b1d2', '\x0c80174edff323088009d8831363b1d2', '\x329e5c640fc98253', '\x329e5c640fc98253', '\xb20defeef11e27bf', '\xb20defeef11e27bf', '\xdf87001e7930c20fc49ba45b4abec021', '\xdf87001e7930c20fc49ba45b4abec021', NULL, '\x976aed50e78c886079d2aeca356c267e275bc8f342505cee', false, false, '\x717c001aca9d6acb', '\x717c001aca9d6acb', '\xd73802f77991ebf3', '\xd73802f77991ebf3', 'V', 'V', '2008-10-02 09:11:20.569342', 'jsmith');
-
-
-ALTER TABLE ccardaud ENABLE TRIGGER ALL;
-
 --
 -- TOC entry 9501 (class 0 OID 0)
 -- Dependencies: 483
@@ -10521,37 +10473,6 @@ ALTER TABLE ccbank ENABLE TRIGGER ALL;
 SELECT pg_catalog.setval('ccbank_ccbank_id_seq', 5, true);
 
 
---
--- TOC entry 9086 (class 0 OID 146568627)
--- Dependencies: 486 9465
--- Data for Name: ccpay; Type: TABLE DATA; Schema: public; Owner: admin
---
-
-ALTER TABLE ccpay DISABLE TRIGGER ALL;
-
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (16, 6, 95, 104.90, true, 'D', 'C', 'A', '40000', 1, '', '40000-1', 'SGS-005000: The server encountered a database error.', 'DECLINED', '', '', '2005-12-28 14:10:03', '', '', NULL, NULL, 0, '2005-12-28 16:49:52.505285', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (20, 6, 95, 997.50, false, 'C', 'C', 'C', '50008', 1, 'NNN', '50008-1', '', 'APPROVED', '1234560003192121:NNN :100009309292:', 'APPROVED', '2006-01-09 07:02:01', '0003192121', '1136815015', NULL, NULL, 0, '2006-01-09 09:54:02.774859', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (17, 6, 95, 104.90, false, 'C', 'C', 'A', '40000', 2, 'NNN', '40000-2', '', 'APPROVED', '1234560003031755:NNN :100009278151:', 'APPROVED', '2005-12-28 14:16:06', '0003031755', '1135804266', NULL, NULL, 0, '2005-12-28 16:56:11.906559', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (18, 6, 95, 9.99, false, 'D', 'C', 'C', '40000', 3, '', '40000-3', 'SGS-002300: This transaction was previously approved.', 'DECLINED', '', 'DUPLICATE APPROVED', '2005-12-28 14:19:36', '', '1135804476', NULL, NULL, 0, '2005-12-28 16:59:18.283679', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (19, 6, 95, 114.89, false, 'C', 'C', 'C', '40000', 4, 'NNN', '40000-4', '', 'APPROVED', '1234560003031809:NNN :100009278170:', 'APPROVED', '2005-12-28 14:22:56', '0003031809', '1135804676', NULL, NULL, 0, '2005-12-28 17:02:37.384347', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (22, 6, 95, 104.90, false, 'D', 'C', 'C', '50009', 1, '', '50009-1', 'SGS-005003: The order already exists in the database.', 'DUPLICATE', '', '', '2006-01-09 07:54:07', '', '', NULL, NULL, 0, '2006-01-09 10:46:12.764421', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (24, 6, 95, 104.90, false, 'C', 'C', 'C', '50031', 1, 'NNN', '50031-1', '', 'APPROVED', '1234560003192673:NNN :100009309363:', 'APPROVED', '2006-01-09 08:00:54', '0003192673', '1136818549', NULL, NULL, 0, '2006-01-09 10:52:56.014269', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (23, 6, 95, 104.90, false, 'C', 'C', 'A', '50009', 2, 'NNN', '50009-2', '', 'APPROVED', '1234560003192610:NNN :100009309346:', 'APPROVED', '2006-01-09 07:54:28', '0003192610', '1136818162', NULL, NULL, 0, '2006-01-09 10:46:29.418547', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (25, 6, 95, 997.50, true, 'X', 'C', 'A', '50043', 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2006-01-13 11:02:53.762333', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (26, 6, 95, 997.50, true, 'X', 'C', 'A', '50043', 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2006-01-13 11:04:04.523402', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (27, 6, 95, 997.50, false, 'X', 'C', 'C', '50043', 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2006-01-13 11:05:13.422812', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (28, 6, 95, 997.50, false, 'C', 'C', 'A', '50043', 4, 'NNN', '50043-4', '', 'APPROVED', '1234560003216021:NNN :100009323145:', 'APPROVED', '2006-01-13 08:59:47', '0003216021', '1137167679', NULL, NULL, 0, '2006-01-13 11:51:43.930367', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (29, 6, 95, 103.86, false, 'C', 'C', 'A', '40005', 1, 'NNN', '40005-1', '', 'APPROVED', '1234560003216040:NNN :100009323812:', 'APPROVED', '2006-01-13 10:49:03', '0003216040', '1137174236', NULL, NULL, 0, '2006-01-13 12:48:58.008', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (30, 6, 95, 103.86, false, 'C', 'C', 'C', '50045', 1, 'NNN', '50045-1', '', 'APPROVED', '1234560003216058:NNN :100009324195:', 'APPROVED', '2006-01-13 11:36:34', '0003216058', '1137177086', NULL, NULL, 0, '2006-01-13 13:36:28.387', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (31, 6, 95, 997.50, false, 'C', 'C', 'C', '50046', 1, 'NNN', '50046-1', '', 'APPROVED', '1234560003216072:NNN :100009325017:', 'APPROVED', '2006-01-13 13:09:36', '0003216072', '1137182667', NULL, NULL, 0, '2006-01-13 15:09:30.383', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (33, 6, 95, 500.00, false, 'D', 'C', 'C', '50047', 1, '', '50047-1', 'SGS-005003: The order already exists in the database.', 'DUPLICATE', '', '', '2006-01-30 09:07:58', '', '', NULL, NULL, 0, '2006-01-30 11:59:39.538476', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (34, 6, 95, 500.00, false, 'C', 'C', 'C', '50148', 1, 'NNN', '50148-1', '', 'APPROVED', '1234560003353787:NNN :100009404491:', 'APPROVED', '2006-01-30 09:14:21', '0003353787', '1138637345', NULL, NULL, 0, '2006-01-30 12:06:01.556067', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (35, 6, 95, 500.00, false, 'X', 'C', 'C', '50149', 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2006-01-30 16:36:06.281219', 'jsmith', 1, NULL);
-INSERT INTO ccpay (ccpay_id, ccpay_ccard_id, ccpay_cust_id, ccpay_amount, ccpay_auth, ccpay_status, ccpay_type, ccpay_auth_charge, ccpay_order_number, ccpay_order_number_seq, ccpay_r_avs, ccpay_r_ordernum, ccpay_r_error, ccpay_r_approved, ccpay_r_code, ccpay_r_message, ccpay_yp_r_time, ccpay_r_ref, ccpay_yp_r_tdate, ccpay_r_tax, ccpay_r_shipping, ccpay_yp_r_score, ccpay_transaction_datetime, ccpay_by_username, ccpay_curr_id, ccpay_ccpay_id) VALUES (54, 7, 95, 1000.00, false, 'C', 'C', 'C', '199', 1, 'passed', '199', NULL, 'APPROVED', '123111', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2008-10-02 09:13:21.509805', 'jsmith', 1, NULL);
-
-
-ALTER TABLE ccpay ENABLE TRIGGER ALL;
-
 --
 -- TOC entry 9503 (class 0 OID 0)
 -- Dependencies: 487
@@ -41081,6 +41002,9 @@ INSERT INTO locale (locale_id, locale_code, locale_descrip, locale_lang_file, lo
 INSERT INTO locale (locale_id, locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES (28, 'Finance', 'Finance', '', 'MM/DD/YY', '999,999,990', '.-,', '', '999,999,990.0000', '999,999,990.0000', '999,999,990.00', 'HH12:MI AM', 'MM/DD/YY HH12:MI AM', NULL, '999,999,990.0000', '999,999,990.0000', '', 'HH2424:MI ', 352, 230, '', '', '', '', '', '', 0, 4, 4, 2, 4, 2, 4, 0, 2, 2);
 INSERT INTO locale (locale_id, locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES (4, 'Spanish', 'Locale for Mexican Spanish', 'OpenMFG.mx.sp', 'DD/MM/YY', '999999990.00', '.-,', '', '999999990.0000', '999999990.0000', '999999990.00', 'HH:MI', 'DD/MM/YY HH:MI', NULL, '999999990.0000', '', '', 'HH24:MI', 354, 140, '', '', '', '', '', '', 2, 4, 0, 2, 4, 2, 4, 0, 2, 2);
 INSERT INTO locale (locale_id, locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES (29, 'UK', 'United Kingdom', '', 'DD/MM/YYYY', '999,999,990.00', '.-,', '', '999,999,990.0000', '999,999,990.0000', '999,999,990.00', 'HH:MI', 'DD/MM/YYYY HH:MI', NULL, '999,999,990.0000', '999,999,990.0000', '999,999,990.00000', 'HH24:MI', 352, 229, '', '', '', '', '', '', 2, 4, 4, 2, 4, 2, 4, 5, 2, 2);
+INSERT INTO locale (locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES ('French', 'French', '', 'DD/MM/YY', '999,999,990.00', ',- ', '', '999,999,990.0000', '999,999,990.0000', '999,999,990.00', 'HH:MI', 'DD/MM/YY HH:MI', NULL, '999,999,990.0000', '999,999,990.0000', '999,999,990.000', 'HH24:MI', 362, 74, '', '', '', '', '', '', 2, 4, 4, 2, 4, 2, 4, 3, 2, 2);
+INSERT INTO locale (locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES ('Chinese', 'Simplified Chinese', '', 'DD/MM/YY', '999,999,990.00', ',- ', '', '999,999,990.0000', '999,999,990.0000', '999,999,990.00', 'HH:MI', 'DD/MM/YY HH:MI', NULL, '999,999,990.0000', '999,999,990.0000', '999,999,990.000', 'HH24:MI', 498, 45, '', '', '', '', '', '', 2, 4, 4, 2, 4, 2, 4, 3, 2, 2);
+--INSERT INTO locale (locale_code, locale_descrip, locale_lang_file, locale_dateformat, locale_currformat, locale_qtyformat, locale_comments, locale_qtyperformat, locale_salespriceformat, locale_extpriceformat, locale_timeformat, locale_timestampformat, local_costformat, locale_costformat, locale_purchpriceformat, locale_uomratioformat, locale_intervalformat, locale_lang_id, locale_country_id, locale_error_color, locale_warning_color, locale_emphasis_color, locale_altemphasis_color, locale_expired_color, locale_future_color, locale_curr_scale, locale_salesprice_scale, locale_purchprice_scale, locale_extprice_scale, locale_cost_scale, locale_qty_scale, locale_qtyper_scale, locale_uomratio_scale, locale_percent_scale, locale_weight_scale) VALUES ('Telugu', 'Telugu', '', 'DD/MM/YY', '999,999,990.00', ',- ', '', '999,999,990.0000', '999,999,990.0000', '999,999,990.00', 'HH:MI', 'DD/MM/YY HH:MI', NULL, '999,999,990.0000', '999,999,990.0000', '999,999,990.000', 'HH24:MI', 472, 100, '', '', '', '', '', '', 2, 4, 4, 2, 4, 2, 4, 3, 2, 2);
 
 
 ALTER TABLE locale ENABLE TRIGGER ALL;
@@ -64080,23 +64004,6 @@ ALTER TABLE payaropen ENABLE TRIGGER ALL;
 -- Data for Name: payco; Type: TABLE DATA; Schema: public; Owner: admin
 --
 
-ALTER TABLE payco DISABLE TRIGGER ALL;
-
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (16, 2964, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (17, 2964, 104.90, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (18, 2964, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (22, 2973, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (23, 2973, 104.90, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (25, 3002, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (26, 3002, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (27, 3002, 0.00, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (28, 3002, 997.50, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (29, 3005, 103.86, 1);
-INSERT INTO payco (payco_ccpay_id, payco_cohead_id, payco_amount, payco_curr_id) VALUES (35, 3023, 0.00, 1);
-
-
-ALTER TABLE payco ENABLE TRIGGER ALL;
-
 --
 -- TOC entry 9639 (class 0 OID 0)
 -- Dependencies: 710
index e75b6b6..d701d61 100644 (file)
@@ -164,7 +164,10 @@ BEGIN
       -1,
       NULL,
       _fc.fincharg_markoninvoice,
-      'Finance Charge Assessment',
+--    - enhance data shown in the item description for the invoice line to indicate which invoice is affected
+--    - Feature Request 23344       
+--      'Finance Charge Assessment',
+      'Finance Charge Assessment - Invoice Number ' || _ar.aropen_docnumber || ' - Past Due Balance ' || (_ar.aropen_amount - _ar.aropen_paid) || ' Due Date - ' || _ar.aropen_duedate,
       1.0,
       1.0,
       pAssessAmount,
index 05f1729..19b0028 100644 (file)
@@ -4,16 +4,15 @@ CREATE OR REPLACE FUNCTION avgCost(pItemsiteid INTEGER) RETURNS NUMERIC AS $$
 DECLARE
   _value NUMERIC;
   _qoh NUMERIC;
-  _qohnn NUMERIC;
 BEGIN
-  SELECT itemsite_value, itemsite_qtyonhand, itemsite_nnqoh
-    INTO _value, _qoh, _qohnn
+  SELECT itemsite_value, itemsite_qtyonhand
+    INTO _value, _qoh
     FROM itemsite
    WHERE(itemsite_id=pItemsiteid);
-  IF (_qoh = 0.0 AND _qohnn = 0.0) THEN
+  IF (_qoh = 0.0) THEN
     RETURN 0.0;
   END IF;
-  RETURN _value / (_qoh + _qohnn);
+  RETURN _value / _qoh;
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
index 8538760..87d9ddf 100644 (file)
@@ -1,12 +1,10 @@
-CREATE OR REPLACE FUNCTION balanceItemsite(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION balanceItemsite(pItemsiteid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
   _itemlocseries INTEGER;
   _balanced NUMERIC;
   _qoh NUMERIC;
-  _nnQoh NUMERIC;
 
 BEGIN
 
@@ -23,39 +21,25 @@ BEGIN
     RETURN -1;
   END IF;
 
---  Calculate the Netable portion
+--  Calculate the qoh
   SELECT COALESCE(SUM(itemloc_qty), 0) INTO _balanced
-  FROM itemloc LEFT OUTER JOIN location ON (itemloc_location_id=location_id)
-  WHERE ( ( (location_id IS NULL) OR (location_netable) )
-   AND (itemloc_itemsite_id=pItemsiteid) );
+  FROM itemloc
+  WHERE (itemloc_itemsite_id=pItemsiteid);
 
---  Post an AD Transaction for the Netable portion
+--  Post an AD Transaction
   SELECT invAdjustment( itemsite_id, (_balanced - itemsite_qtyonhand),
                         'Balance', 'Inventory Balance' ) INTO _itemlocseries
   FROM itemsite
   WHERE (itemsite_id=pItemsiteid);
 
---  Post the invtrans records associated with the itemlocdist records
-  PERFORM postInvhist(itemlocdist_invhist_id)
-     FROM itemlocdist
-    WHERE(itemlocdist_series=_itemlocseries);
+--  Post the itemloc series which will postIntoTrialBalance and postInvHist
+  PERFORM postItemlocSeries(_itemlocseries);
 
 --  Kill the resultant distribution records
   DELETE FROM itemlocdist
   WHERE (itemlocdist_series=_itemlocseries);
 
---  Calculate and write the Non-Netable portion directly
-  SELECT COALESCE(SUM(itemloc_qty), 0) INTO _nnQoh
-  FROM itemloc, location
-  WHERE ( (itemloc_location_id=location_id)
-   AND (NOT location_netable)
-   AND (itemloc_itemsite_id=pItemsiteid) );
-
-  UPDATE itemsite
-  SET itemsite_nnqoh = _nnQoh
-  WHERE (itemsite_id=pItemsiteid);
-
   RETURN 1;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
diff --git a/foundation-database/public/functions/bankreconciliation.sql b/foundation-database/public/functions/bankreconciliation.sql
new file mode 100644 (file)
index 0000000..b670282
--- /dev/null
@@ -0,0 +1,361 @@
+CREATE OR REPLACE FUNCTION bankReconciliation(pBankrecid INTEGER, pTask TEXT) RETURNS INTEGER AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+-- posting and reopening bank reconciliations are nearly identical.
+-- the main differences revolve around what cleanup is done before starting.
+-- other than that, posting and reopening touch the same g/l accounts but with
+-- debits and credits reversed.
+DECLARE
+  _accntid      INTEGER;
+  _bankrecid    INTEGER;
+  _gltransid    INTEGER;
+  _post         BOOLEAN;
+  _r            RECORD;
+  _result       INTEGER;
+  _sequence     INTEGER;
+  _sign         INTEGER := 1;
+  _tax          RECORD;
+
+BEGIN
+
+  CASE lower(pTask)
+    WHEN 'post'   THEN _post = TRUE;
+    WHEN 'reopen' THEN _post = FALSE;
+    ELSE RAISE EXCEPTION
+          'bankReconciliation got an invalid task %1 [xtuple: bankReconciliation, -2, %2]',
+          pTask, pTask;
+  END CASE;
+
+  -- Check the accnt information to make sure it is valid
+  SELECT accnt_id INTO _accntid
+    FROM bankrec
+    JOIN bankaccnt ON (bankrec_bankaccnt_id=bankaccnt_id)
+    JOIN accnt     ON (bankaccnt_accnt_id=accnt_id)
+   WHERE (bankrec_id=pBankrecid);
+  IF ( NOT FOUND ) THEN
+    RAISE EXCEPTION 'bankReconciliation %1 %2 did not find the bank''s G/L account [xtuple: bankReconciliation, -1, %3, %4]',
+                    pTask, pBankrecid, pTask, pBankrecid;
+  END IF;
+
+  IF _post THEN
+    DELETE FROM bankrecitem
+     WHERE ( (NOT bankrecitem_cleared)
+       AND   (bankrecitem_bankrec_id=pBankrecid) );
+
+    -- Post any cleared bankadj items and convert the bankrecitem
+    FOR _r IN SELECT bankrecitem_id, bankrecitem_source_id
+                FROM bankrecitem, bankadj
+               WHERE ( (bankrecitem_source = 'AD')
+                 AND   (bankrecitem_source_id=bankadj_id)
+                 AND   (bankrecitem_cleared)
+                 AND   (NOT bankadj_posted)
+                 AND   (bankrecitem_bankrec_id=pBankrecid) ) LOOP
+
+      _sequence := postBankAdjustment(_r.bankrecitem_source_id);
+
+      IF (_sequence < 0) THEN
+        RAISE EXCEPTION 'postBankAdjustment %1 %2 failed during bankReconciliation [xtuple: postBankAdjustment, -10, %3, %4, %5]',
+                         pTask, pBankrecid, pTask, pBankrecid, _sequence;
+      END IF;
+
+      SELECT gltrans_id INTO _gltransid
+        FROM gltrans
+       WHERE ( (gltrans_sequence=_sequence)
+         AND   (gltrans_accnt_id=_accntid) );
+      IF ( NOT FOUND ) THEN
+        RAISE EXCEPTION 'bankReconciliation %1 %2 did not find exactly one gltrans record for %3 [xtuple: bankReconciliation, -11, %4, %5, %6]',
+                        pTask, pBankrecid, _sequence, pTask, pBankrecid, _sequence;
+      END IF;
+
+      UPDATE bankrecitem
+         SET bankrecitem_source = 'GL',
+             bankrecitem_source_id=_gltransid
+       WHERE (bankrecitem_id=_r.bankrecitem_id);
+
+    END LOOP;
+
+  ELSE -- NOT _post, therefore must be reopen
+    _sign := -1;
+    SELECT bankrec_id INTO _bankrecid
+      FROM bankrec
+     WHERE (NOT bankrec_posted);
+    IF (FOUND) THEN
+      -- Delete any bankrecitem records for unposted periods
+      DELETE FROM bankrecitem
+       WHERE (bankrecitem_bankrec_id=_bankrecid);
+      -- Delete any bankrec records for unposted period
+      DELETE FROM bankrec
+       WHERE (bankrec_id=_bankrecid);
+    END IF;
+  END IF;
+
+  IF (fetchMetricBool('CashBasedTax')) THEN
+    -- Cash based tax distributions
+    -- GL Transactions
+    SELECT fetchGLSequence() INTO _sequence;
+    FOR _r IN SELECT *
+              FROM bankrecitem
+             WHERE ( (bankrecitem_cleared)
+               AND   (bankrecitem_bankrec_id=pBankrecid) ) LOOP
+      -- first, debit the tax liability clearing account
+      -- and credit the tax liability distribution account
+      -- for each tax code
+      FOR _tax IN SELECT docnumber, custname, distdate, source, doctype,
+                         tax_sales_accnt_id, tax_dist_accnt_id,
+                         ROUND(currToBase(currid, ROUND(SUM(taxhist_tax),2), taxhist_docdate) * percentpaid, 2) AS taxbasevalue
+                  FROM (
+                        -- Cash receipt, gltrans
+                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
+                               aropen_curr_id AS currid, gltrans_date AS distdate,
+                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
+                               gltrans_source AS source, gltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
+                                                    AND (gltrans_doctype='CR')
+                                                    AND (gltrans_misc_id=cashrcpt_id))
+                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
+                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
+                                     JOIN custinfo ON (cust_id=aropen_cust_id)
+                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
+                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        -- Cash receipt, sltrans
+                        UNION
+                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
+                               aropen_curr_id AS currid, sltrans_date AS distdate,
+                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
+                               sltrans_source AS source, sltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
+                                                    AND (sltrans_doctype='CR')
+                                                    AND (sltrans_misc_id=cashrcpt_id))
+                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
+                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
+                                     JOIN custinfo ON (cust_id=aropen_cust_id)
+                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
+                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (sltrans_id=_r.bankrecitem_source_id)
+                        -- Cash payment, gltrans
+                        UNION
+                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
+                               apopen_curr_id AS currid, gltrans_date AS distdate,
+                               (vohead_amount / apopen_amount) AS percentpaid,
+                               gltrans_source AS source, gltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
+                                                    AND (gltrans_doctype='CK')
+                                                    AND (gltrans_misc_id=checkhead_id))
+                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                     JOIN vohead ON (vohead_number=apopen_docnumber)
+                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
+                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        UNION
+                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
+                               apopen_curr_id AS currid, gltrans_date AS distdate,
+                               (vohead_amount / apopen_amount) AS percentpaid,
+                               gltrans_source AS source, gltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
+                                                    AND (gltrans_doctype='CK')
+                                                    AND (gltrans_misc_id=checkhead_id))
+                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                     JOIN vohead ON (vohead_number=apopen_docnumber)
+                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
+                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
+                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        -- Cash payment, sltrans
+                        UNION
+                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
+                               apopen_curr_id AS currid, sltrans_date AS distdate,
+                               (vohead_amount / apopen_amount) AS percentpaid,
+                               sltrans_source AS source, sltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
+                                                    AND (sltrans_doctype='CK')
+                                                    AND (sltrans_misc_id=checkhead_id))
+                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                     JOIN vohead ON (vohead_number=apopen_docnumber)
+                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
+                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (sltrans_id=_r.bankrecitem_source_id)
+                        UNION
+                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
+                               apopen_curr_id AS currid, sltrans_date AS distdate,
+                               (vohead_amount / apopen_amount) AS percentpaid,
+                               sltrans_source AS source, sltrans_doctype AS doctype,
+                               tax_sales_accnt_id, tax_dist_accnt_id,
+                               taxhist_tax, taxhist_docdate
+                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
+                                                    AND (sltrans_doctype='CK')
+                                                    AND (sltrans_misc_id=checkhead_id))
+                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                     JOIN vohead ON (vohead_number=apopen_docnumber)
+                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
+                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
+                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
+                                     JOIN tax ON (tax_id=taxhist_tax_id)
+                        WHERE (sltrans_id=_r.bankrecitem_source_id)
+                       ) AS data
+                  GROUP BY docnumber, custname, currid, distdate, percentpaid,
+                           source, doctype,
+                           tax_sales_accnt_id, tax_dist_accnt_id, taxhist_docdate
+      LOOP
+        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
+                                   _tax.tax_dist_accnt_id, 
+                                   _tax.taxbasevalue * _sign,
+                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
+        IF (_result < 0) THEN
+          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
+        END IF;
+        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
+                                   _tax.tax_sales_accnt_id, 
+                                   (_tax.taxbasevalue * -1.0 * _sign),
+                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
+        IF (_result < 0) THEN
+          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
+        END IF;
+      END LOOP;
+
+      -- second, create a taxpay row for each taxhist
+      FOR _tax IN SELECT taxhist_id, applyid, distdate,
+                         ROUND(taxhist_tax * percentpaid, 2) AS taxpaid
+                  FROM (
+                        -- Cash receipt, gltrans
+                        SELECT taxhist_id, aropen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
+                               (cashrcptitem_amount / aropen_amount) AS percentpaid
+                          FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
+                                                      AND (gltrans_doctype='CR')
+                                                      AND (gltrans_misc_id=cashrcpt_id))
+                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
+                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
+                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
+                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
+                          WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        -- Cash receipt, sltrans
+                        UNION
+                        SELECT taxhist_id, aropen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
+                               (cashrcptitem_amount / aropen_amount) AS percentpaid
+                          FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
+                                                      AND (sltrans_doctype='CR')
+                                                      AND (sltrans_misc_id=cashrcpt_id))
+                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
+                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
+                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
+                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
+                          WHERE (sltrans_id=_r.bankrecitem_source_id)
+                        -- Cash payment, gltrans
+                        UNION
+                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
+                               (checkitem_amount / apopen_amount) AS percentpaid
+                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
+                                                       AND (gltrans_doctype='CK')
+                                                       AND (gltrans_misc_id=checkhead_id))
+                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                       JOIN vohead ON (vohead_number=apopen_docnumber)
+                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
+                          WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        UNION
+                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
+                               (checkitem_amount / apopen_amount) AS percentpaid
+                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
+                                                       AND (gltrans_doctype='CK')
+                                                       AND (gltrans_misc_id=checkhead_id))
+                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                       JOIN vohead ON (vohead_number=apopen_docnumber)
+                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
+                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
+                          WHERE (gltrans_id=_r.bankrecitem_source_id)
+                        -- Cash payment, sltrans
+                        UNION
+                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
+                               (checkitem_amount / apopen_amount) AS percentpaid
+                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
+                                                       AND (sltrans_doctype='CK')
+                                                       AND (sltrans_misc_id=checkhead_id))
+                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                       JOIN vohead ON (vohead_number=apopen_docnumber)
+                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
+                          WHERE (sltrans_id=_r.bankrecitem_source_id)
+                        UNION
+                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
+                               (checkitem_amount / apopen_amount) AS percentpaid
+                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
+                                                       AND (sltrans_doctype='CK')
+                                                       AND (sltrans_misc_id=checkhead_id))
+                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
+                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
+                                       JOIN vohead ON (vohead_number=apopen_docnumber)
+                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
+                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
+                          WHERE (sltrans_id=_r.bankrecitem_source_id)
+                       ) AS data
+      LOOP
+        IF _post THEN
+          INSERT INTO taxpay
+          ( taxpay_taxhist_id, taxpay_apply_id, taxpay_distdate, taxpay_tax )
+          VALUES
+          ( _tax.taxhist_id, _tax.applyid, COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.taxpaid );
+        ELSE
+          DELETE FROM taxpay
+          WHERE ((taxpay_taxhist_id=_tax.taxhist_id)
+             AND (taxpay_apply_id=_tax.applyid)
+             AND (taxpay_distdate=COALESCE(_r.bankrecitem_effdate, _tax.distdate))
+             AND (taxpay_tax=_tax.taxpaid));
+        END IF;
+      END LOOP;
+
+    END LOOP;
+
+    SELECT postGLSeries(_sequence, fetchJournalNumber('GL-MISC')) INTO _result;
+    IF (_result < 0) THEN
+      RAISE EXCEPTION 'postGLSeries failed, result=%', _result;
+    END IF;
+
+  END IF;
+
+  UPDATE gltrans
+     SET gltrans_rec = _post
+   WHERE ( (gltrans_id IN (SELECT bankrecitem_source_id
+                             FROM bankrecitem
+                            WHERE ((bankrecitem_source = 'GL')
+                              AND  (bankrecitem_cleared)
+                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
+     AND   (gltrans_accnt_id=_accntid) ) ;
+
+  UPDATE sltrans
+     SET sltrans_rec = _post
+   WHERE ( (sltrans_id IN (SELECT bankrecitem_source_id
+                             FROM bankrecitem
+                            WHERE ((bankrecitem_source = 'SL')
+                              AND  (bankrecitem_cleared)
+                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
+     AND   (sltrans_accnt_id=_accntid) ) ;
+
+  UPDATE bankrec SET 
+    bankrec_posted = _post,
+    bankrec_postdate = CASE _post WHEN TRUE THEN now() ELSE NULL END
+   WHERE (bankrec_id=pBankrecid);
+
+  RETURN pBankrecid;
+END;
+$$ LANGUAGE 'plpgsql';
+
index fb79c3f..a60452d 100644 (file)
@@ -37,7 +37,7 @@ BEGIN
   WHERE (invcitem_invchead_id=pInvcheadid);
 
   IF (pType IN ('T', 'X')) THEN
-    SELECT SUM(tax) INTO _tax
+    SELECT COALESCE(SUM(tax), 0.0) INTO _tax
     FROM (SELECT COALESCE(ROUND(SUM(taxdetail_tax), 2), 0.0) AS tax
           FROM tax
                JOIN calculateTaxDetailSummary('I', pInvcheadid, 'T')ON (taxdetail_tax_id=tax_id)
index 0f4def9..cf11cab 100644 (file)
@@ -41,7 +41,7 @@ BEGIN
     AND (coitem_status != 'X');
 
   IF (pType IN ('T', 'B', 'X')) THEN
-    SELECT SUM(tax) INTO _tax
+    SELECT COALESCE(SUM(tax), 0.0) INTO _tax
     FROM (SELECT COALESCE(ROUND(SUM(taxdetail_tax), 2), 0.0) AS tax
           FROM tax
                JOIN calculateTaxDetailSummary('S', pCoheadid, 'T')ON (taxdetail_tax_id=tax_id)
index bf15b9b..e26484e 100644 (file)
@@ -4,6 +4,8 @@ CREATE OR REPLACE FUNCTION convertQuote(INTEGER) RETURNS INTEGER AS $$
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
   pQuheadid ALIAS FOR $1;
+  _qunumber TEXT;
+  _ponumber TEXT;
   _soheadid INTEGER;
   _soitemid INTEGER;
   _orderid INTEGER;
@@ -62,13 +64,20 @@ BEGIN
     RETURN -5;
   END IF;
 
-  IF ( (_usespos) AND (NOT _blanketpos) ) THEN
-    PERFORM cohead_id
-    FROM quhead JOIN cohead ON ( (cohead_cust_id=quhead_cust_id) AND
-                                 (UPPER(cohead_custponumber)=UPPER(quhead_custponumber)) )
+  IF (_usespos) THEN
+    SELECT quhead_number, COALESCE(quhead_custponumber, ''), cohead_id INTO _qunumber, _ponumber, _soheadid
+    FROM quhead LEFT OUTER JOIN cohead ON ( (cohead_cust_id=quhead_cust_id) AND
+                                            (UPPER(cohead_custponumber)=UPPER(quhead_custponumber)) )
     WHERE (quhead_id=pQuheadid);
-    IF (FOUND) THEN
-      RAISE EXCEPTION 'Duplicate Customer PO';
+    IF (_ponumber = '') THEN
+      RAISE EXCEPTION 'Customer PO required for Quote % [xtuple: convertQuote, -7, %]',
+                      _qunumber, _qunumber;
+    END IF;
+  
+    IF ( (NOT _blanketpos) AND (_soheadid IS NOT NULL) ) THEN
+      RAISE EXCEPTION 'Duplicate Customer PO % for Quote % [xtuple: convertQuote, -8, %, %]',
+                      _ponumber, _qunumber,
+                      _ponumber, _qunumber;
     END IF;
   END IF;
   
@@ -180,7 +189,7 @@ BEGIN
     AND   (comment_source_id=pQuheadid) );
 
   FOR _r IN SELECT quitem.*,
-                   quhead_number, quhead_prj_id,
+                   quhead_number, quhead_prj_id, quhead_saletype_id,
                    itemsite_item_id, itemsite_leadtime,
                    itemsite_createsopo, itemsite_createsopr,
                    item_type, COALESCE(quitem_itemsrc_id, itemsrc_id, -1) AS itemsrcid
@@ -215,7 +224,8 @@ BEGIN
 
     IF (fetchMetricBool('enablextcommissionission')) THEN
       PERFORM xtcommission.getSalesReps(quhead_cust_id, quhead_shipto_id,
-                                        _r.itemsite_item_id, _r.quitem_price,
+                                        _r.itemsite_item_id, _r.quhead_saletype_id,
+                                        _r.quitem_price, _r.quitem_custprice,
                                         _soitemid, 'SalesItem')
       FROM quhead
       WHERE (quhead_id=pQuheadid);
index 5c68dc2..22c8c21 100644 (file)
@@ -4,6 +4,8 @@ CREATE OR REPLACE FUNCTION convertQuoteToInvoice(INTEGER) RETURNS INTEGER AS $$
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
   pQuheadid ALIAS FOR $1;
+  _qunumber TEXT;
+  _ponumber TEXT;
   _iheadid INTEGER;
   _iitemid INTEGER;
   _orderid INTEGER;
@@ -67,17 +69,47 @@ BEGIN
   END IF;
 
 -- PO/blanket PO checks
+  IF (_usespos) THEN
+    SELECT quhead_number, COALESCE(quhead_custponumber, ''), invchead_id INTO _qunumber, _ponumber, _iheadid
+    FROM quhead LEFT OUTER JOIN invchead ON ( (invchead_cust_id=quhead_cust_id) AND
+                                              (UPPER(invchead_ponumber)=UPPER(quhead_custponumber)) )
+    WHERE (quhead_id=pQuheadid);
+    IF (_ponumber = '') THEN
+      RAISE EXCEPTION 'Customer PO required for Quote % [xtuple: convertQuote, -7, %]',
+                      _qunumber, _qunumber;
+    END IF;
+  
+    IF ( (NOT _blanketpos) AND (_iheadid IS NOT NULL) ) THEN
+      RAISE EXCEPTION 'Duplicate Customer PO % for Quote % [xtuple: convertQuote, -8, %, %]',
+                      _ponumber, _qunumber,
+                      _ponumber, _qunumber;
+    END IF;
+  END IF;
+  
 
+  IF (_usespos) THEN
+    SELECT quhead_number INTO _qunumber
+    FROM quhead
+    WHERE (quhead_id=pQuheadid)
+      AND (COALESCE(quhead_custponumber, '') = '');
+    IF (FOUND) THEN
+      RAISE EXCEPTION 'Customer PO required for Quote % [xtuple: convertQuote, -7, %]',
+                      _qunumber, _qunumber;
+    END IF;
+  END IF;
+  
   IF ( (_usespos) AND (NOT _blanketpos) ) THEN
-    PERFORM invchead_id
+    SELECT quhead_number, quhead_custponumber INTO _qunumber, _ponumber
     FROM quhead JOIN invchead ON ( (invchead_cust_id=quhead_cust_id) AND
-                                 (UPPER(invchead_custponumber)=UPPER(quhead_custponumber)) )
+                                   (UPPER(invchead_ponumber)=UPPER(quhead_custponumber)) )
     WHERE (quhead_id=pQuheadid);
     IF (FOUND) THEN
-      RAISE EXCEPTION 'Duplicate Customer PO';
+      RAISE EXCEPTION 'Duplicate Customer PO % for Quote % [xtuple: convertQuote, -8, %, %]',
+                      _ponumber, _qunumber,
+                      _ponumber, _qunumber;
     END IF;
   END IF;
-
+  
 --Check to see if an invoice exists with the quote number
   
   PERFORM quhead_number, invchead_id 
@@ -182,7 +214,7 @@ BEGIN
 */
 
   FOR _r IN SELECT quitem.*,
-                   quhead_number, quhead_prj_id,
+                   quhead_number, quhead_prj_id, quhead_saletype_id,
                    itemsite_item_id, itemsite_leadtime,
                    itemsite_createsopo, itemsite_createsopr,
                    item_type, COALESCE(quitem_itemsrc_id, itemsrc_id, -1) AS itemsrcid
@@ -220,7 +252,8 @@ BEGIN
 
     IF (fetchMetricBool('enablextcommissionission')) THEN
       PERFORM xtcommission.getSalesReps(quhead_cust_id, quhead_shipto_id,
-                                        _r.itemsite_item_id, _r.quitem_price,
+                                        _r.itemsite_item_id, _r.quhead_saletype_id,
+                                        _r.quitem_price, _r.quitem_custprice,
                                         _iitemid, 'InvoiceItem')
       FROM quhead
       WHERE (quhead_id=pQuheadid);
index 7a8e316..764f5b8 100644 (file)
@@ -1,24 +1,22 @@
-CREATE OR REPLACE FUNCTION copyItemSite(pitemsiteid INTEGER,
-                                        pdestwhsid INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION copyItemSite(pItemsiteid INTEGER,
+                                        pDestWhsid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
 BEGIN
 
-  RETURN copyItemSite(pitemsiteid, pdestwhsid, NULL);
+  RETURN copyItemSite(pItemsiteid, pDestWhsid, NULL);
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
 
-CREATE OR REPLACE FUNCTION copyItemSite(pitemsiteid INTEGER,
-                                        pdestwhsid INTEGER,
-                                        pdestitemid INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION copyItemSite(pItemsiteid INTEGER,
+                                        pDestWhsid INTEGER,
+                                        pDestItemid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pitemsiteid ALIAS FOR $1;
-  pdestwhsid  ALIAS FOR $2;
   _destwhs  whsinfo%ROWTYPE;
   _new    itemsite%ROWTYPE;
   _supplywarehousid INTEGER := NULL;
@@ -27,16 +25,16 @@ BEGIN
   -- make a copy of the old itemsite
   SELECT * INTO _new
   FROM itemsite
-  WHERE (itemsite_id=pitemsiteid);
+  WHERE (itemsite_id=pItemsiteid);
   IF (NOT FOUND) THEN
     RETURN -1;
   END IF;
 
   -- if there is no dest warehouse then perhaps the user is manually copying it
-  IF (pdestwhsid IS NOT NULL) THEN
+  IF (pDestWhsid IS NOT NULL) THEN
     SELECT * INTO _destwhs
     FROM whsinfo
-    WHERE (warehous_id=pdestwhsid);
+    WHERE (warehous_id=pDestWhsid);
     IF (NOT FOUND) THEN
       RETURN -2;
     END IF;
@@ -48,9 +46,9 @@ BEGIN
 
   SELECT itemsite_id INTO _new.itemsite_id
   FROM itemsite
-  WHERE ((itemsite_item_id=COALESCE(pdestitemid, _new.itemsite_item_id))
-    AND  (itemsite_warehous_id=pdestwhsid OR
-    (itemsite_warehous_id IS NULL AND pdestwhsid IS NULL)));
+  WHERE ((itemsite_item_id=COALESCE(pDestItemid, _new.itemsite_item_id))
+    AND  (itemsite_warehous_id=pDestWhsid OR
+    (itemsite_warehous_id IS NULL AND pDestWhsid IS NULL)));
   IF (FOUND) THEN
     RETURN _new.itemsite_id;
   END IF;
@@ -64,18 +62,17 @@ BEGIN
       SELECT itemsite_id INTO _new.itemsite_supply_itemsite_id
       FROM itemsite
       WHERE (itemsite_warehous_id=_supplywarehousid)
-        AND (itemsite_item_id=pdestitemid);
+        AND (itemsite_item_id=pDestItemid);
     END IF;
   END IF;
 
   -- now override the things we know have to change
   _new.itemsite_id                   := NEXTVAL('itemsite_itemsite_id_seq');
-  _new.itemsite_warehous_id          := pdestwhsid;
+  _new.itemsite_warehous_id          := pDestWhsid;
   _new.itemsite_qtyonhand            := 0;
   _new.itemsite_value                := 0;
   _new.itemsite_datelastcount        := NULL;
   _new.itemsite_datelastused         := NULL;
-  _new.itemsite_nnqoh                := 0;
   _new.itemsite_location_id          := -1;
   _new.itemsite_recvlocation_id      := -1;
   _new.itemsite_issuelocation_id     := -1;
@@ -111,7 +108,6 @@ BEGIN
     _new.itemsite_location           := NULL;
     _new.itemsite_location_comments  := NULL;
     _new.itemsite_notes              := 'Transit Warehouse';
-    _new.itemsite_nnqoh              := 0;
     _new.itemsite_createwo           := FALSE;
     _new.itemsite_costcat_id         := _destwhs.warehous_costcat_id;
     _new.itemsite_supply_itemsite_id := NULL;
@@ -138,7 +134,7 @@ BEGIN
     itemsite_soldranking,            itemsite_createpr,
     itemsite_location,               itemsite_location_comments,
     itemsite_notes,                  itemsite_perishable,
-    itemsite_nnqoh,                  itemsite_autoabcclass,
+    itemsite_autoabcclass,
     itemsite_ordergroup,             itemsite_disallowblankwip,
     itemsite_maxordqty,              itemsite_mps_timefence,
     itemsite_createwo,               itemsite_warrpurc,
@@ -150,7 +146,7 @@ BEGIN
     itemsite_location_dist,          itemsite_recvlocation_dist,
     itemsite_issuelocation_dist
   ) VALUES (
-    _new.itemsite_id,                COALESCE(pdestitemid, _new.itemsite_item_id),
+    _new.itemsite_id,                COALESCE(pDestItemid, _new.itemsite_item_id),
     _new.itemsite_warehous_id,         _new.itemsite_qtyonhand,
     _new.itemsite_costmethod,        _new.itemsite_value,
     _new.itemsite_reorderlevel,      _new.itemsite_ordertoqty,
@@ -170,7 +166,7 @@ BEGIN
     _new.itemsite_soldranking,         _new.itemsite_createpr,
     _new.itemsite_location,          _new.itemsite_location_comments,
     _new.itemsite_notes,             _new.itemsite_perishable,
-    _new.itemsite_nnqoh,             _new.itemsite_autoabcclass,
+    _new.itemsite_autoabcclass,
     _new.itemsite_ordergroup,        _new.itemsite_disallowblankwip,
     _new.itemsite_maxordqty,         _new.itemsite_mps_timefence,
     _new.itemsite_createwo,          _new.itemsite_warrpurc,
@@ -185,4 +181,4 @@ BEGIN
 
   RETURN _new.itemsite_id;
 END;
-$$ LANGUAGE 'plpgsql';
\ No newline at end of file
+$$ LANGUAGE plpgsql;
\ No newline at end of file
index c4b42cd..edbc609 100644 (file)
@@ -1,8 +1,7 @@
-CREATE OR REPLACE FUNCTION deleteItemSite(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION deleteItemSite(pItemsiteid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
   _result INTEGER;
   _lotserial BOOLEAN;
   _bbom BOOLEAN;
@@ -11,7 +10,7 @@ DECLARE
 
 BEGIN
 
-  IF ( ( SELECT ( (itemsite_qtyonhand <> 0) OR (itemsite_nnqoh <> 0) )
+  IF ( ( SELECT (itemsite_qtyonhand <> 0)
          FROM itemsite
          WHERE (itemsite_id=pItemsiteid) ) ) THEN
     RETURN -9;
@@ -210,4 +209,4 @@ BEGIN
   RETURN 0;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 0eafa94..5a37354 100644 (file)
@@ -1,6 +1,9 @@
 CREATE OR REPLACE FUNCTION detailedNNQOH(INTEGER, BOOLEAN) RETURNS NUMERIC AS '
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
+--
+-- Deprecated
+--
 DECLARE
   pItemsiteid ALIAS FOR $1;
   pABS ALIAS FOR $2;
index aea3e77..d18a526 100644 (file)
@@ -1,30 +1,27 @@
-CREATE OR REPLACE FUNCTION detailedQOH(INTEGER, BOOLEAN) RETURNS NUMERIC AS '
+CREATE OR REPLACE FUNCTION detailedQOH(pItemsiteid INTEGER,
+                                       pABS BOOLEAN) RETURNS NUMERIC AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
-  pABS ALIAS FOR $2;
   _qoh NUMERIC;
 
 BEGIN
 
   IF (pABS) THEN
     SELECT SUM(noNeg(itemloc_qty)) INTO _qoh
-    FROM itemloc LEFT OUTER JOIN location ON (itemloc_location_id=location_id)
-    WHERE ( ( (location_id IS NULL) OR (location_netable) )
-     AND (itemloc_itemsite_id=pItemsiteid) );
+    FROM itemloc
+    WHERE (itemloc_itemsite_id=pItemsiteid);
   ELSE
     SELECT SUM(itemloc_qty) INTO _qoh
-    FROM itemloc LEFT OUTER JOIN location ON (itemloc_location_id=location_id)
-    WHERE ( ( (location_id IS NULL) OR (location_netable) )
-     AND (itemloc_itemsite_id=pItemsiteid) );
+    FROM itemloc
+    WHERE (itemloc_itemsite_id=pItemsiteid);
   END IF;
 
   IF (_qoh IS NULL) THEN
-    _qoh := 0;
+    _qoh := 0.0;
   END IF;
 
   RETURN _qoh;
 
 END;
-' LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 01ed663..0165aab 100644 (file)
@@ -1,8 +1,7 @@
-CREATE OR REPLACE FUNCTION distributeItemlocSeries(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION distributeItemlocSeries(pItemlocSeries INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemlocSeries   ALIAS FOR $1;
   _distCounter     INTEGER;
   _itemlocdist     RECORD;
   _itemlocid       INTEGER;
@@ -135,50 +134,6 @@ BEGIN
         WHERE (itemloc_id=_itemlocid);
       END IF;
 
---  Adjust QOH if this itemlocdist is to/from a non-netable location
-      IF ( SELECT (NOT location_netable)
-           FROM itemloc, location
-           WHERE ( (itemloc_location_id=location_id)
-            AND (itemloc_id=_itemlocid) ) ) THEN
-
---  Record the netable->non-netable (or visaveras) invhist
-        SELECT NEXTVAL('invhist_invhist_id_seq') INTO _invhistid;
-        INSERT INTO invhist
-        ( invhist_id, invhist_itemsite_id, 
-          invhist_transtype, invhist_invqty,
-          invhist_qoh_before, invhist_qoh_after,
-          invhist_docnumber, invhist_comments,
-          invhist_invuom, invhist_unitcost,
-          invhist_costmethod, invhist_value_before, invhist_value_after,
-          invhist_series ) 
-        SELECT _invhistid, itemsite_id, 
-               'NN', (_itemlocdist.qty * -1),
-               itemsite_qtyonhand, (itemsite_qtyonhand - _itemlocdist.qty),
-               invhist_docnumber, invhist_comments,
-               uom_name, stdCost(item_id),
-               itemsite_costmethod, itemsite_value,
-               (itemsite_value + (_itemlocdist.qty * -1 * CASE WHEN(itemsite_costmethod='A') THEN avgcost(itemsite_id)
-                                                               ELSE stdCost(itemsite_item_id)
-                                                          END)),
-               _itemlocdist.series
-        FROM item, itemsite, invhist, uom
-        WHERE ((itemsite_item_id=item_id)
-         AND (item_inv_uom_id=uom_id)
-         AND (itemsite_controlmethod <> 'N')
-         AND (itemsite_id=_itemlocdist.itemsiteid)
-         AND (invhist_id=_itemlocdist.invhistid));
-
---  Adjust the parent itemsite
-        IF (NOT _itemlocdist.itemsite_freeze) THEN
-          UPDATE itemsite
-          SET itemsite_qtyonhand = (itemsite_qtyonhand - _itemlocdist.qty),
-              itemsite_nnqoh = (itemsite_nnqoh + _itemlocdist.qty)
-          FROM itemloc
-          WHERE ((itemloc_itemsite_id=itemsite_id)
-           AND (itemloc_id=_itemlocid));
-        END IF;
-      END IF;
-
     END IF;
 
 --  If, after the distribution, the target itemloc_qty = 0, delete the itemloc
@@ -197,4 +152,4 @@ BEGIN
   RETURN _distCounter;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 5d3fad9..61d8577 100644 (file)
@@ -1,8 +1,7 @@
-CREATE OR REPLACE FUNCTION distributeToLocations(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION distributeToLocations(pItemlocdistid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemlocdistid ALIAS FOR $1;
   _distCounter INTEGER;
   _itemlocdist RECORD;
   _itemlocid INTEGER;
@@ -147,49 +146,6 @@ BEGIN
       END IF;
     END IF;
 
---  Adjust QOH if this itemlocdist is to/from a non-netable location
-    IF ( SELECT (NOT location_netable)
-         FROM itemloc, location
-         WHERE ((itemloc_location_id=location_id)
-          AND (itemloc_id=_itemlocid)) ) THEN
-
---  Record the invhist record for the netable->non-netable (or visaversa)
-      INSERT INTO invhist
-      ( invhist_itemsite_id,
-        invhist_transtype, invhist_invqty,
-        invhist_qoh_before, invhist_qoh_after,
-        invhist_docnumber, invhist_comments,
-        invhist_invuom, invhist_unitcost,
-        invhist_costmethod, invhist_value_before, invhist_value_after,
-        invhist_series )
-      SELECT itemsite_id,
-             'NN', (_itemlocdist.qty * -1),
-             itemsite_qtyonhand, (itemsite_qtyonhand - _itemlocdist.qty),
-             invhist_docnumber, invhist_comments,
-             uom_name, stdCost(item_id),
-             itemsite_costmethod, itemsite_value,
-             (itemsite_value + (_itemlocdist.qty * -1 * CASE WHEN(itemsite_costmethod='A') THEN avgcost(itemsite_id)
-                                                             ELSE stdCost(itemsite_item_id)
-                                                        END)),
-             _itemlocdist.series
-      FROM item, itemsite, invhist, uom
-      WHERE ( (itemsite_item_id=item_id)
-       AND (item_inv_uom_id=uom_id)
-       AND (itemsite_controlmethod <> 'N')
-       AND (itemsite_id=_itemlocdist.itemsiteid)
-       AND (invhist_id=_itemlocdist.invhistid) );
-
---  Update the itemsite_qoh
-      IF (NOT _itemlocdist.itemsite_freeze) THEN
-        UPDATE itemsite
-        SET itemsite_qtyonhand = (itemsite_qtyonhand - _itemlocdist.qty),
-            itemsite_nnqoh = (itemsite_nnqoh + _itemlocdist.qty)
-        FROM itemloc
-        WHERE ((itemloc_itemsite_id=itemsite_id)
-         AND (itemloc_id=_itemlocid));
-      END IF;
-    END IF;
-
 --  Cache the running qty.
     _runningQty := _runningQty + _itemlocdist.qty;
 
@@ -226,4 +182,4 @@ BEGIN
   RETURN _distCounter;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index da84dd2..5b6e3c2 100644 (file)
@@ -124,32 +124,6 @@ BEGIN
              '', pMemo,
              0);
 
-      IF (_item.itemsite_createsopr) THEN
-        SELECT createPR(cohead_number::INTEGER, 'S', _coitemid) INTO _orderid
-        FROM cohead
-        WHERE (cohead_id=pSoheadid);
-        IF (_orderid > 0) THEN
-          UPDATE coitem SET coitem_order_id=_orderid
-          WHERE (coitem_id=_coitemid);
-        ELSE
-          RAISE EXCEPTION 'Could not explode kit. CreatePR failed, result=%', _orderid; 
-        END IF;
-      END IF;
-
-      IF (_item.itemsite_createsopo) THEN
-        SELECT itemsrc_id INTO _itemsrcid
-        FROM itemsrc
-        WHERE ((itemsrc_item_id=_item.item_id)
-        AND (itemsrc_default));
-
-        GET DIAGNOSTICS _count = ROW_COUNT;
-        IF (_count > 0) THEN
-          PERFORM createPurchaseToSale(_coitemid, _itemsrcid, _item.itemsite_dropship);
-        ELSE
-          RAISE WARNING 'One or more Kit items are flagged as purchase-to-order for this site, but no default item source is defined.';
-        END IF;
-      END IF;
-     
     END IF;
   END LOOP;
 
index 888b310..63f1e16 100644 (file)
@@ -1,10 +1,11 @@
 
-CREATE OR REPLACE FUNCTION fetchNextCheckNumber(INTEGER) RETURNS INTEGER AS '
+CREATE OR REPLACE FUNCTION fetchNextCheckNumber(pBankaccntid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
   pBankaccntid ALIAS FOR $1;
   _nextChkNumber INTEGER;
+  _checkheadid INTEGER;
 
 BEGIN
 
@@ -12,6 +13,18 @@ BEGIN
   FROM bankaccnt
   WHERE (bankaccnt_id=pBankaccntid);
 
+  WHILE (TRUE) LOOP
+    SELECT checkhead_id INTO _checkheadid
+    FROM checkhead
+    WHERE (checkhead_number=_nextChkNumber)
+      AND (checkhead_bankaccnt_id=pBankaccntid);
+    IF (NOT FOUND) THEN
+      EXIT;
+    ELSE
+      _nextChkNumber := _nextChkNumber + 1;
+    END IF;
+  END LOOP;
+
   UPDATE bankaccnt
   SET bankaccnt_nextchknum = (bankaccnt_nextchknum + 1)
   WHERE (bankaccnt_id=pBankaccntid);
@@ -19,5 +32,5 @@ BEGIN
   RETURN _nextChkNumber;
 
 END;
-' LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
index 62da625..a9cd679 100644 (file)
@@ -22,7 +22,7 @@ BEGIN
                                              AND  (invcitem_item_id=itemsite_item_id)
                                              AND  (invcitem_warehous_id=itemsite_warehous_id)
                                              AND  (invcitem_linenumber=coitem_linenumber))) > 0)) THEN 'P'
-            WHEN (coitem_status='O' AND (itemsite_qtyonhand - qtyAllocated(itemsite_id, CURRENT_DATE)
+            WHEN (coitem_status='O' AND (qtyAvailable(itemsite_id) - qtyAllocated(itemsite_id, CURRENT_DATE)
                                          + qtyOrdered(itemsite_id, CURRENT_DATE))
                                           >= ((coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) * coitem_qty_invuomratio)) THEN 'R'
             ELSE coitem_status END
diff --git a/foundation-database/public/functions/importbankreccleared.sql b/foundation-database/public/functions/importbankreccleared.sql
new file mode 100644 (file)
index 0000000..4fddd3e
--- /dev/null
@@ -0,0 +1,182 @@
+
+CREATE OR REPLACE FUNCTION importBankrecCleared(pBankrecid INTEGER) RETURNS INTEGER AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _bankrecid INTEGER;
+  _result INTEGER := 0;
+  _cleared BOOLEAN;
+  _doctype TEXT;
+  _docid INTEGER := -1;
+  _bankadjid INTEGER := -1;
+  _debitbankadjtypeid INTEGER := -1;
+  _creditbankadjtypeid INTEGER := -1;
+  _b RECORD;
+  _r RECORD;
+
+BEGIN
+  -- cache some information
+  IF (pBankrecid = -1) THEN
+    _bankrecid := fetchMetricValue('ImportBankRecId');
+  ELSE
+    _bankrecid := pBankrecid;
+  END IF;
+
+  SELECT * INTO _b
+  FROM bankrec JOIN bankaccnt ON (bankaccnt_id=bankrec_bankaccnt_id)
+  WHERE (bankrec_id=_bankrecid);
+  IF (NOT FOUND) THEN
+    RAISE EXCEPTION 'bankrec not found';
+  END IF;
+  IF (_b.bankrec_posted) THEN
+    RAISE EXCEPTION 'bankrec already posted';
+  END IF;
+
+   _debitbankadjtypeid := fetchMetricValue('ImportBankRecDebitAdj');
+  IF (_debitbankadjtypeid = -1) THEN
+    RAISE EXCEPTION 'Metric ImportBankRecDebitAdj not defined [xtuple: reconcileBankAccount, -1]';
+  END IF;
+
+   _creditbankadjtypeid := fetchMetricValue('ImportBankRecCreditAdj');
+  IF (_creditbankadjtypeid = -1) THEN
+    RAISE EXCEPTION 'Metric ImportBankRecCreditAdj not defined [xtuple: reconcileBankAccount, -2]';
+  END IF;
+
+  -- loop thru bankrecimport and toggle cleared items
+  FOR _r IN
+  SELECT *,
+         COALESCE(bankrecimport_debit_amount, 0.0) AS debit,
+         COALESCE(bankrecimport_credit_amount, 0.0) AS credit
+  FROM bankrecimport
+-- TODO how to handle multiple bank accounts
+--  WHERE (bankrecimport_?=_b.bankaccnt=?)
+  LOOP
+
+    -- TODO how to handle duplicate document numbers
+    -- TODO how to handle amount differences
+    -- TODO add support for Project Accounting (sltrans)
+
+    IF ( (_r.debit > 0.0) AND (_r.credit > 0.0) ) THEN
+      RAISE NOTICE 'Bankrecimport % cannot determine if debit or credit', _r.bankrecimport_reference;
+      CONTINUE;
+    END IF;
+
+    IF (_r.debit > 0.0) THEN
+
+      -- handle receipts
+
+      SELECT cashrcpt_id INTO _docid
+      FROM cashrcpt
+      WHERE (cashrcpt_docnumber=_r.bankrecimport_reference)
+        AND (cashrcpt_posted)
+        AND (NOT cashrcpt_void)
+      -- TODO workaround for duplicates
+      ORDER BY cashrcpt_id DESC
+      LIMIT 1;
+      IF (FOUND) THEN
+        SELECT toggleBankrecCleared(_b.bankrec_id, 'GL', gltrans_id,
+                                    cashrcpt_curr_rate, _r.debit,
+                                    _r.bankrecimport_effdate) INTO _cleared
+        FROM gltrans LEFT OUTER JOIN bankrecitem ON (bankrecitem_source='GL' AND
+                                                     bankrecitem_source_id=gltrans_id)
+        WHERE (gltrans_source='A/R')
+          AND (gltrans_doctype='CR')
+          AND (gltrans_misc_id=_docid)
+          AND (NOT gltrans_rec)
+          AND (gltrans_accnt_id=_b.bankaccnt_accnt_id)
+          AND (NOT COALESCE(bankrecitem_cleared, FALSE));
+      ELSE
+
+        -- create and toggle bank adjustment
+        -- TODO define bank adjustment names
+
+        _bankadjid := -1;
+        SELECT bankadj_id INTO _bankadjid
+        FROM bankadj JOIN bankadjtype ON (bankadjtype_id=bankadj_bankadjtype_id)
+        WHERE (bankadjtype_id=_debitbankadjtypeid)
+          AND (bankadj_docnumber=_r.bankrecimport_reference)
+          AND (bankadj_bankaccnt_id=_b.bankaccnt_id);
+        IF (NOT FOUND) THEN
+          INSERT INTO bankadj
+            (bankadj_bankaccnt_id, bankadj_bankadjtype_id, bankadj_date,
+             bankadj_docnumber, bankadj_amount, bankadj_notes,
+             bankadj_curr_id)
+          VALUES
+            (_b.bankaccnt_id, _debitbankadjtypeid, _r.bankrecimport_effdate,
+             _r.bankrecimport_reference, _r.debit, 'Import Bankrec Adjustment',
+             _b.bankaccnt_curr_id)
+          RETURNING bankadj_id INTO _bankadjid;
+        END IF;
+
+        SELECT toggleBankrecCleared(_b.bankrec_id, 'AD', _bankadjid,
+                                    1.0, _r.debit,
+                                    _r.bankrecimport_effdate) INTO _cleared
+        FROM bankadj LEFT OUTER JOIN bankrecitem ON (bankrecitem_source='AD' AND
+                                                     bankrecitem_source_id=bankadj_id)
+        WHERE (bankadj_id=_bankadjid)
+          AND (NOT COALESCE(bankrecitem_cleared, FALSE));
+      END IF;
+
+      -- done with receipts
+
+    ELSE
+
+      -- handle checks
+
+      SELECT checkhead_id INTO _docid
+      FROM checkhead
+      WHERE (checkhead_number::TEXT=_r.bankrecimport_reference)
+        AND (checkhead_posted)
+        AND (NOT checkhead_void);
+      IF (FOUND) THEN
+        SELECT toggleBankrecCleared(_b.bankrec_id, 'GL', gltrans_id,
+                                    checkhead_curr_rate, _r.credit,
+                                    _r.bankrecimport_effdate) INTO _cleared
+        FROM gltrans LEFT OUTER JOIN bankrecitem ON (bankrecitem_source='GL' AND
+                                                     bankrecitem_source_id=gltrans_id)
+        WHERE (gltrans_source='A/P')
+          AND (gltrans_doctype='CK')
+          AND (gltrans_misc_id=_docid)
+          AND (NOT gltrans_rec)
+          AND (gltrans_accnt_id=_b.bankaccnt_accnt_id)
+          AND (NOT COALESCE(bankrecitem_cleared, FALSE));
+      ELSE
+
+        -- create and toggle bank adjustment
+        -- TODO define bank adjustment names
+
+        _bankadjid := -1;
+        SELECT bankadj_id INTO _bankadjid
+        FROM bankadj JOIN bankadjtype ON (bankadjtype_id=bankadj_bankadjtype_id)
+        WHERE (bankadjtype_id=_creditbankadjtypeid)
+          AND (bankadj_docnumber=_r.bankrecimport_reference);
+        IF (NOT FOUND) THEN
+          INSERT INTO bankadj
+            (bankadj_bankaccnt_id, bankadj_bankadjtype_id, bankadj_date,
+             bankadj_docnumber, bankadj_amount, bankadj_notes,
+             bankadj_curr_id)
+          VALUES
+            (_b.bankaccnt_id, _creditbankadjtypeid, _r.bankrecimport_effdate,
+             _r.bankrecimport_reference, _r.credit, 'Import Bankrec Adjustment',
+             _b.bankaccnt_curr_id)
+          RETURNING bankadj_id INTO _bankadjid;
+        END IF;
+
+        SELECT toggleBankrecCleared(_b.bankrec_id, 'AD', _bankadjid,
+                                    1.0, _r.credit,
+                                    _r.bankrecimport_effdate) INTO _cleared
+        FROM bankadj LEFT OUTER JOIN bankrecitem ON (bankrecitem_source='AD' AND
+                                                     bankrecitem_source_id=_bankadjid)
+        WHERE (NOT COALESCE(bankrecitem_cleared, FALSE));
+      END IF;
+
+      -- done with checks
+
+    END IF;
+
+  END LOOP;
+
+  RETURN _result;
+END;
+$$ LANGUAGE 'plpgsql';
+
index 66243e1..7c40758 100644 (file)
@@ -24,7 +24,7 @@ BEGIN
     --get top level works orders
     FOR _x IN
        SELECT wo_id,wo_number,wo_subnumber,wo_status,wo_startdate,
-         wo_duedate,wo_adhoc,wo_itemsite_id,itemsite_qtyonhand,
+         wo_duedate,wo_adhoc,wo_itemsite_id,qtyAvailable(itemsite_id) AS availableqoh,
          wo_qtyord,wo_qtyrcv,wo_prodnotes, item_number,
          item_descrip1, item_descrip2, item_listprice, uom_name
        FROM wo, itemsite, item, uom     
@@ -47,7 +47,7 @@ BEGIN
         _row.wodata_itemsite_id := _x.wo_itemsite_id;
         _row.wodata_custprice := _x.item_listprice;
         _row.wodata_listprice := _x.item_listprice;
-        _row.wodata_qoh := _x.itemsite_qtyonhand;
+        _row.wodata_qoh := _x.availableqoh;
         _row.wodata_short := noneg(_x.wo_qtyord - _x.wo_qtyrcv);
         _row.wodata_qtyrcv := _x.wo_qtyrcv;   
         _row.wodata_qtyordreq := _x.wo_qtyord;   
@@ -149,7 +149,7 @@ BEGIN
     _level := (plevel + 1);    
     --find all WO with the ordid of the next level up
     _qry := 'SELECT wo_id,wo_number,wo_subnumber,wo_status,wo_startdate,wo_duedate,
-         wo_adhoc,wo_itemsite_id,itemsite_qtyonhand,wo_qtyord,wo_qtyrcv, wo_prodnotes,
+         wo_adhoc,wo_itemsite_id,qtyAvailable(itemsite_id) AS availableqoh,wo_qtyord,wo_qtyrcv, wo_prodnotes,
          item_number,item_descrip1, item_descrip2, item_listprice, uom_name,
          womatl_qtyiss, womatl_scrap, womatl_wooper_id
        FROM itemsite,  wo, item, uom, womatl 
@@ -184,7 +184,7 @@ BEGIN
         _row.wodata_itemsite_id := _x.wo_itemsite_id;        
         _row.wodata_custprice := _x.item_listprice;
         _row.wodata_listprice := _x.item_listprice;
-        _row.wodata_qoh := _x.itemsite_qtyonhand;
+        _row.wodata_qoh := _x.availableqoh;
         _row.wodata_short := noneg(_x.wo_qtyord - _x.wo_qtyrcv);
         _row.wodata_qtyiss := _x.womatl_qtyiss;  
         _row.wodata_qtyrcv := _x.wo_qtyrcv;   
index 53042e3..8155994 100644 (file)
@@ -40,7 +40,7 @@ BEGIN
 
   _qry := 'SELECT womatl_id, wo_number, wo_subnumber, 
       wo_startdate, womatl_duedate, womatl_itemsite_id,
-      itemsite_qtyonhand, womatl_qtyreq, womatl_qtyiss,
+      qtyAvailable(itemsite_id) AS availableqoh, womatl_qtyreq, womatl_qtyiss,
       womatl_qtyper, womatl_qtyreq, womatl_scrap,
       womatl_ref, womatl_notes, womatl_price, item_listprice,
       item_number, item_descrip1, item_descrip2,
@@ -78,11 +78,11 @@ BEGIN
     _subrow.wodata_itemsite_id := _subx.womatl_itemsite_id;    
     _subrow.wodata_custprice := _subx.womatl_price;
     _subrow.wodata_listprice := _subx.item_listprice;
-    _subrow.wodata_qoh := _subx.itemsite_qtyonhand;
-    IF((_subx.itemsite_qtyonhand > (_subx.womatl_qtyreq - _subx.womatl_qtyiss))) THEN
+    _subrow.wodata_qoh := _subx.availableqoh;
+    IF((_subx.availableqoh > (_subx.womatl_qtyreq - _subx.womatl_qtyiss))) THEN
       _subrow.wodata_short := 0;
     ELSE
-      _subrow.wodata_short := (_subx.womatl_qtyreq - _subx.womatl_qtyiss) -  _subx.itemsite_qtyonhand;
+      _subrow.wodata_short := (_subx.womatl_qtyreq - _subx.womatl_qtyiss) -  _subx.availableqoh;
     END IF;
     _subrow.wodata_qtyper := _subx.womatl_qtyper;
     _subrow.wodata_qtyiss := _subx.womatl_qtyiss;         
index 6c796f7..b1f2e74 100644 (file)
@@ -1,9 +1,8 @@
-CREATE OR REPLACE FUNCTION initialDistribution(INTEGER, INTEGER) RETURNS INTEGER  AS $$
+CREATE OR REPLACE FUNCTION initialDistribution(pItemsiteid INTEGER,
+                                               pLocationid INTEGER) RETURNS INTEGER  AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
-  pLocationid ALIAS FOR $2;
   _itemlocid INTEGER;
   _invhistid INTEGER;
   _itemlocSeries INTEGER;
@@ -65,37 +64,6 @@ BEGIN
       ( _invhistid, pLocationid, _r.itemloc_ls_id,
         _r.itemloc_qty, 0, _r.itemloc_qty );
 
---  Adjust QOH if this itemlocdist is to/from a non-netable location
-      IF ( SELECT (NOT location_netable)
-           FROM location
-           WHERE (location_id=pLocationid) ) THEN
-
-        INSERT INTO invhist
-        ( invhist_itemsite_id, invhist_series,
-          invhist_transtype, invhist_invqty,
-          invhist_qoh_before, invhist_qoh_after,
-          invhist_comments,
-          invhist_invuom, invhist_unitcost,
-          invhist_costmethod, invhist_value_before, invhist_value_after  ) 
-        SELECT itemsite_id, _itemlocSeries,
-               'NN', (_r.itemloc_qty * -1),
-               _r.itemloc_qty, 0,
-               'Initial Distribution',
-               uom_name, stdCost(item_id),
-               itemsite_costmethod, itemsite_value, itemsite_value
-        FROM itemsite, item, uom
-        WHERE ( (itemsite_item_id=item_id)
-         AND (item_inv_uom_id=uom_id)
-         AND (itemsite_controlmethod <> 'N')
-         AND (itemsite_id=pItemsiteid) );
-
-        UPDATE itemsite
-        SET itemsite_nnqoh = (itemsite_nnqoh + _r.itemloc_qty),
-            itemsite_qtyonhand = (itemsite_qtyonhand - _r.itemloc_qty) 
-        WHERE (itemsite_id=pItemsiteid);
-
-      END IF;
-
     END LOOP;
 
   ELSE
@@ -144,43 +112,9 @@ BEGIN
     FROM itemsite
     WHERE (itemsite_id=pItemsiteid);
 
---  Adjust QOH if this itemlocdist is to/from a non-netable location
-    IF ( SELECT (NOT location_netable)
-         FROM location
-         WHERE (location_id=pLocationid) ) THEN
-
-      INSERT INTO invhist
-      ( invhist_itemsite_id, invhist_series,
-        invhist_transtype, invhist_invqty,
-        invhist_qoh_before, invhist_qoh_after,
-        invhist_comments,
-        invhist_invuom, invhist_unitcost,
-        invhist_costmethod, invhist_value_before, invhist_value_after  ) 
-      SELECT itemsite_id, _itemlocSeries,
-             'NN', (itemloc_qty * -1),
-             itemloc_qty, 0,
-             'Initial Distribution',
-             uom_name, stdCost(item_id),
-             itemsite_costmethod, itemsite_value, itemsite_value
-      FROM itemloc, itemsite, item, uom
-      WHERE ( (itemsite_item_id=item_id)
-       AND (item_inv_uom_id=uom_id)
-       AND (itemsite_controlmethod <> 'N')
-       AND (itemloc_itemsite_id=itemsite_id)
-       AND (itemloc_id=_itemlocid) );
-
-      UPDATE itemsite
-      SET itemsite_nnqoh = itemsite_qtyonhand,
-          itemsite_qtyonhand = 0 
-      FROM itemloc
-      WHERE ( (itemloc_itemsite_id=itemsite_id)
-       AND (itemloc_id=_itemlocid) );
-
-    END IF;
-
   END IF;
 
   RETURN _itemlocid;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 03cef38..ab7931a 100644 (file)
@@ -18,7 +18,7 @@ DECLARE
   _cost NUMERIC := 0.0;
 BEGIN
   -- cache item info
-  SELECT * INTO _r
+  SELECT *, itemInvPriceRat(item_id) AS itempriceinvrat INTO _r
   FROM itemsite, item
   WHERE (itemsite_item_id=pItemid)
     AND (itemsite_warehous_id=pSiteid)
@@ -33,7 +33,7 @@ BEGIN
       AND (bomitem_rev_id=getActiveRevid('BOM', _r.item_id))
       AND (pEffective BETWEEN bomitem_effective AND (bomitem_expires - 1));
   ELSEIF (fetchMetricBool('WholesalePriceCosting')) THEN
-    _cost := _r.item_listcost;
+    _cost := _r.item_listcost / _r.itempriceinvrat;
   ELSE
     SELECT itemcost(_r.itemsite_id) INTO _cost;
   END IF;
index 4469198..77e3340 100644 (file)
@@ -1,8 +1,7 @@
-CREATE OR REPLACE FUNCTION itemInventoryUOMInUse(INTEGER) RETURNS BOOLEAN AS '
+CREATE OR REPLACE FUNCTION itemInventoryUOMInUse(pItemid INTEGER) RETURNS BOOLEAN AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemid ALIAS FOR $1;
   _uomid INTEGER;
   _result INTEGER;
 BEGIN
@@ -20,7 +19,7 @@ BEGIN
 
   SELECT itemsite_id INTO _result
   FROM itemsite WHERE ( (itemsite_item_id=pItemid)
-                  AND   ((itemsite_qtyonhand <> 0) OR (itemsite_nnqoh <> 0)) )
+                  AND   (itemsite_qtyonhand <> 0) )
   LIMIT 1;
   IF (FOUND) THEN
     RETURN TRUE;
@@ -28,4 +27,4 @@ BEGIN
 
   RETURN FALSE;
 END;
-' LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index f7ef3bc..93bfe05 100644 (file)
@@ -18,7 +18,7 @@ DECLARE
   _item RECORD;
   _cust RECORD;
   _shipto RECORD;
-  _iteminvpricerat NUMERIC := 1.0;
+  _itempricepricerat NUMERIC := 1.0;
   _listprice NUMERIC := 0.0;
   _qty NUMERIC;
   _asof DATE;
@@ -38,7 +38,7 @@ BEGIN
   _asof := COALESCE(pAsOf, CURRENT_DATE);
 
 --  Cache Item, Customer and Shipto
-  SELECT item.*, itemCost(itemsite_id) AS invcost INTO _item
+  SELECT item.*, (itemCost(itemsite_id) / itemuomtouomratio(item_id, item_inv_uom_id, item_price_uom_id)) AS invcost INTO _item
   FROM item LEFT OUTER JOIN itemsite ON (itemsite_item_id=item_id AND itemsite_warehous_id=pSiteid)
   WHERE (item_id=pItemid);
 
@@ -52,7 +52,7 @@ BEGIN
 
 -- Get a value here so we do not have to call the function several times
   SELECT itemuomtouomratio(pItemid, pPriceUOM, _item.item_price_uom_id) AS ratio
-    INTO _iteminvpricerat;
+    INTO _itempricepricerat;
 
 -- First get a sales price if any so we when we find other prices
 -- we can determine if we want that price or this price.
@@ -64,15 +64,15 @@ BEGIN
          CASE WHEN (ipsitem_type = 'N') THEN
                (ipsitem_price * itemuomtouomratio(_item.item_id, pPriceUOM, ipsitem_price_uom_id))
               WHEN (ipsitem_type = 'D') THEN
-               noNeg(_item.item_listprice - (_item.item_listprice * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount) * _iteminvpricerat
+               noNeg(_item.item_listprice - (_item.item_listprice * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount) * _itempricepricerat
               WHEN ((ipsitem_type = 'M') AND _long30markups AND _wholesalepricecosting) THEN
-               (_item.item_listcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+               (_item.item_listcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
               WHEN ((ipsitem_type = 'M') AND _long30markups) THEN
-               (_item.invcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+               (_item.invcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
               WHEN (ipsitem_type = 'M' AND _wholesalepricecosting) THEN
-               (_item.item_listcost + (_item.item_listcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+               (_item.item_listcost + (_item.item_listcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
               WHEN (ipsitem_type = 'M') THEN
-               (_item.invcost + (_item.invcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+               (_item.invcost + (_item.invcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
               ELSE 0.00
          END AS ipsprice_price,
          CASE WHEN (ipsitem_item_id=_item.item_id) THEN itemuomtouom(ipsitem_item_id, ipsitem_qty_uom_id, NULL, ipsitem_qtybreak)
@@ -115,15 +115,15 @@ BEGIN
            CASE WHEN (ipsitem_type = 'N') THEN
                  (ipsitem_price * itemuomtouomratio(_item.item_id, pPriceUOM, ipsitem_price_uom_id))
                 WHEN (ipsitem_type = 'D') THEN
-                 noNeg(_item.item_listprice - (_item.item_listprice * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount) * _iteminvpricerat
+                 noNeg(_item.item_listprice - (_item.item_listprice * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount) * _itempricepricerat
                 WHEN ((ipsitem_type = 'M') AND _long30markups AND _wholesalepricecosting) THEN
-                 (_item.item_listcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+                 (_item.item_listcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
                 WHEN ((ipsitem_type = 'M') AND _long30markups) THEN
-                 (_item.invcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+                 (_item.invcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
                 WHEN (ipsitem_type = 'M' AND _wholesalepricecosting) THEN
-                 (_item.item_listcost + (_item.item_listcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+                 (_item.item_listcost + (_item.item_listcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
                 WHEN (ipsitem_type = 'M') THEN
-                 (_item.invcost + (_item.invcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _iteminvpricerat
+                 (_item.invcost + (_item.invcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount) * _itempricepricerat
                 ELSE 0.00
            END AS protoprice,
            CASE WHEN (ipsitem_item_id=_item.item_id) THEN itemuomtouom(ipsitem_item_id, ipsitem_qty_uom_id, NULL, ipsitem_qtybreak)
index 31856f0..d57867a 100644 (file)
@@ -1,326 +1,8 @@
-
-CREATE OR REPLACE FUNCTION postBankReconciliation(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION postBankReconciliation(pBankrecid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
-DECLARE
-  pBankrecid ALIAS FOR $1;
-  _accntid INTEGER;
-  _sequence INTEGER;
-  _gltransid INTEGER;
-  _result INTEGER;
-  _r RECORD;
-  _tax RECORD;
-
 BEGIN
-
--- Check the accnt information to make sure it is valid
-  SELECT accnt_id INTO _accntid
-    FROM bankrec, bankaccnt, accnt
-   WHERE ( (bankaccnt_accnt_id=accnt_id)
-     AND   (bankrec_bankaccnt_id=bankaccnt_id)
-     AND   (bankrec_id=pBankrecid) );
-  IF ( NOT FOUND ) THEN
-    RETURN -1;
-  END IF;
-
--- Delete any bankrecitem records that are not marked as cleared for cleanliness
-  DELETE FROM bankrecitem
-   WHERE ( (NOT bankrecitem_cleared)
-     AND   (bankrecitem_bankrec_id=pBankrecid) );
-
--- Post any bankadj items that were marked as cleared and convert the bankrecitem
-  FOR _r IN SELECT bankrecitem_id, bankrecitem_source_id
-              FROM bankrecitem, bankadj
-             WHERE ( (bankrecitem_source = 'AD')
-               AND   (bankrecitem_source_id=bankadj_id)
-               AND   (bankrecitem_cleared)
-               AND   (NOT bankadj_posted)
-               AND   (bankrecitem_bankrec_id=pBankrecid) ) LOOP
-
-    SELECT postBankAdjustment(_r.bankrecitem_source_id) INTO _sequence;
-
-    IF (_sequence < 0) THEN
-      RETURN -10;
-    END IF;
-
-    SELECT gltrans_id INTO _gltransid
-      FROM gltrans
-     WHERE ( (gltrans_sequence=_sequence)
-       AND   (gltrans_accnt_id=_accntid) );
-    IF ( NOT FOUND ) THEN
-      RETURN -11;
-    END IF;
-
-    UPDATE bankrecitem
-       SET bankrecitem_source = 'GL',
-           bankrecitem_source_id=_gltransid
-     WHERE (bankrecitem_id=_r.bankrecitem_id);
-
-  END LOOP;
-
-  IF (fetchMetricBool('CashBasedTax')) THEN
-    -- Cash based tax distributions
-    -- GL Transactions
-    SELECT fetchGLSequence() INTO _sequence;
-    FOR _r IN SELECT *
-              FROM bankrecitem
-             WHERE ( (bankrecitem_cleared)
-               AND   (bankrecitem_bankrec_id=pBankrecid) ) LOOP
-      -- first, debit the tax liability clearing account
-      -- and credit the tax liability distribution account
-      -- for each tax code
-      FOR _tax IN SELECT docnumber, custname, distdate, source, doctype,
-                         tax_sales_accnt_id, tax_dist_accnt_id,
-                         ROUND(currToBase(currid, ROUND(SUM(taxhist_tax),2), taxhist_docdate) * percentpaid, 2) AS taxbasevalue
-                  FROM (
-                        -- Cash receipt, gltrans
-                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
-                               aropen_curr_id AS currid, gltrans_date AS distdate,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
-                                                    AND (gltrans_doctype='CR')
-                                                    AND (gltrans_misc_id=cashrcpt_id))
-                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                     JOIN custinfo ON (cust_id=aropen_cust_id)
-                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash receipt, sltrans
-                        UNION
-                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
-                               aropen_curr_id AS currid, sltrans_date AS distdate,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
-                                                    AND (sltrans_doctype='CR')
-                                                    AND (sltrans_misc_id=cashrcpt_id))
-                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                     JOIN custinfo ON (cust_id=aropen_cust_id)
-                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, gltrans
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, gltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
-                                                    AND (gltrans_doctype='CK')
-                                                    AND (gltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, gltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
-                                                    AND (gltrans_doctype='CK')
-                                                    AND (gltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, sltrans
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, sltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
-                                                    AND (sltrans_doctype='CK')
-                                                    AND (sltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, sltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
-                                                    AND (sltrans_doctype='CK')
-                                                    AND (sltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                       ) AS data
-                  GROUP BY docnumber, custname, currid, distdate, percentpaid,
-                           source, doctype,
-                           tax_sales_accnt_id, tax_dist_accnt_id, taxhist_docdate
-      LOOP
-        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
-                                   _tax.tax_dist_accnt_id, 
-                                   _tax.taxbasevalue,
-                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
-        IF (_result < 0) THEN
-          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
-        END IF;
-        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
-                                   _tax.tax_sales_accnt_id, 
-                                   (_tax.taxbasevalue * -1.0),
-                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
-        IF (_result < 0) THEN
-          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
-        END IF;
-      END LOOP;
-
-      -- second, create a taxpay row for each taxhist
-      FOR _tax IN SELECT taxhist_id, applyid, distdate,
-                         ROUND(taxhist_tax * percentpaid, 2) AS taxpaid
-                  FROM (
-                        -- Cash receipt, gltrans
-                        SELECT taxhist_id, aropen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid
-                          FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
-                                                      AND (gltrans_doctype='CR')
-                                                      AND (gltrans_misc_id=cashrcpt_id))
-                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash receipt, sltrans
-                        UNION
-                        SELECT taxhist_id, aropen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid
-                          FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
-                                                      AND (sltrans_doctype='CR')
-                                                      AND (sltrans_misc_id=cashrcpt_id))
-                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, gltrans
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
-                                                       AND (gltrans_doctype='CK')
-                                                       AND (gltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
-                                                       AND (gltrans_doctype='CK')
-                                                       AND (gltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, sltrans
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
-                                                       AND (sltrans_doctype='CK')
-                                                       AND (sltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
-                                                       AND (sltrans_doctype='CK')
-                                                       AND (sltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                       ) AS data
-      LOOP
-        INSERT INTO taxpay
-        ( taxpay_taxhist_id, taxpay_apply_id, taxpay_distdate, taxpay_tax )
-        VALUES
-        ( _tax.taxhist_id, _tax.applyid, COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.taxpaid );
-      END LOOP;
-
-    END LOOP;
-
-    SELECT postGLSeries(_sequence, fetchJournalNumber('GL-MISC')) INTO _result;
-    IF (_result < 0) THEN
-      RAISE EXCEPTION 'postGLSeries failed, result=%', _result;
-    END IF;
-
-  END IF;
-
-
--- Mark all the gltrans items that have been cleared as reconciled.
-  UPDATE gltrans
-     SET gltrans_rec = TRUE
-   WHERE ( (gltrans_id IN (SELECT bankrecitem_source_id
-                             FROM bankrecitem
-                            WHERE ((bankrecitem_source = 'GL')
-                              AND  (bankrecitem_cleared)
-                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
-     AND   (gltrans_accnt_id=_accntid) ) ;
-
--- Mark all the sltrans items that have been cleared as reconciled.
-  UPDATE sltrans
-     SET sltrans_rec = TRUE
-   WHERE ( (sltrans_id IN (SELECT bankrecitem_source_id
-                             FROM bankrecitem
-                            WHERE ((bankrecitem_source = 'SL')
-                              AND  (bankrecitem_cleared)
-                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
-     AND   (sltrans_accnt_id=_accntid) ) ;
-
--- Mark the bankrec record as posted
-  UPDATE bankrec SET 
-    bankrec_posted = TRUE,
-    bankrec_postdate = now()
-   WHERE (bankrec_id=pBankrecid);
-
-  RETURN pBankrecid;
+  RETURN bankReconciliation(pBankrecid, 'post');
 END;
 $$ LANGUAGE 'plpgsql';
 
index 5fe1b70..f132e8f 100644 (file)
@@ -46,17 +46,14 @@ BEGIN
     END IF;
   END IF;
 
-  SELECT cashrcpt_cust_id, (cust_number||'-'||cust_name) AS custnote,
-         cashrcpt_fundstype, cashrcpt_number, cashrcpt_docnumber,
-         cashrcpt_distdate, cashrcpt_amount, cashrcpt_discount,
+  SELECT cashrcpt.*,
+         (cust_number||'-'||cust_name) AS custnote,
          (cashrcpt_amount / cashrcpt_curr_rate) AS cashrcpt_amount_base,
-        (cashrcpt_discount / cashrcpt_curr_rate) AS cashrcpt_discount_base,
-         cashrcpt_notes,
+         (cashrcpt_discount / cashrcpt_curr_rate) AS cashrcpt_discount_base,
          cashrcpt_bankaccnt_id AS bankaccnt_id,
          accnt_id AS prepaid_accnt_id,
-         cashrcpt_usecustdeposit,
-         COALESCE(cashrcpt_applydate, cashrcpt_distdate) AS applydate,
-         cashrcpt_curr_id, cashrcpt_curr_rate, cashrcpt_posted, cashrcpt_void INTO _p
+         COALESCE(cashrcpt_applydate, cashrcpt_distdate) AS applydate
+       INTO _p
   FROM cashrcpt LEFT OUTER JOIN custinfo ON (cashrcpt_cust_id=cust_id)
                 LEFT OUTER JOIN accnt ON (accnt_id=findPrepaidAccount(cashrcpt_cust_id))
   WHERE ( (findPrepaidAccount(cashrcpt_cust_id)=0 OR accnt_id > 0) -- G/L interface might be disabled
@@ -337,6 +334,24 @@ BEGIN
                      _p.cashrcpt_distdate,
                      _p.custnote, pCashrcptid );
 
+  -- Post any gain/loss from the alternate currency exchange rate
+  IF (COALESCE(_p.cashrcpt_alt_curr_rate, 0.0) <> 0.0) THEN
+    _exchGain := ROUND((_p.cashrcpt_amount / _p.cashrcpt_alt_curr_rate) -
+                       (_p.cashrcpt_amount / _p.cashrcpt_curr_rate), 2);
+
+    IF (_exchGain <> 0) THEN
+      PERFORM insertIntoGLSeries( _sequence, 'A/R', 'CR',
+                          (_p.cashrcpt_fundstype || '-' || _p.cashrcpt_docnumber),
+                          _debitAccntid, (_exchGain * -1.0),
+                          _p.cashrcpt_distdate, _p.custnote, pCashrcptid );      
+                          
+      PERFORM insertIntoGLSeries( _sequence, 'A/R', 'CR',
+                          (_p.cashrcpt_fundstype || '-' || _p.cashrcpt_docnumber),
+                          getGainLossAccntId(_debitAccntid), _exchGain,
+                          _p.cashrcpt_distdate, _p.custnote, pCashrcptid );      
+    END IF;
+  END IF;
+
   PERFORM postGLSeries(_sequence, pJournalNumber);
 
   -- convert the cashrcptitem records to applications against the cm/cd if we are _predist
index 9a077d1..7765875 100644 (file)
@@ -270,6 +270,23 @@ BEGIN
                              round(_p.checkhead_amount_base, 2),
                               _p.checkhead_checkdate, _gltransNote, pcheckid );
 
+  -- Post any gain/loss from the alternate currency exchange rate
+  IF (COALESCE(_p.checkhead_alt_curr_rate, 0.0) <> 0.0) THEN
+    _exchGain := ROUND((_p.checkhead_curr_rate - _p.checkhead_alt_curr_rate) * _p.checkhead_amount_base, 2);
+
+    IF (_exchGain <> 0) THEN
+      PERFORM insertIntoGLSeries( _sequence, _t.checkrecip_gltrans_source, 'CK',
+                          CAST(_p.checkhead_number AS TEXT),
+                          _p.bankaccntid, (_exchGain * -1.0),
+                          _p.checkhead_checkdate, _gltransNote, pcheckid );      
+                          
+      PERFORM insertIntoGLSeries( _sequence, _t.checkrecip_gltrans_source, 'CK',
+                          CAST(_p.checkhead_number AS TEXT),
+                          getGainLossAccntId(_p.bankaccntid), _exchGain,
+                          _p.checkhead_checkdate, _gltransNote, pcheckid );      
+    END IF;
+  END IF;
+
   PERFORM postGLSeries(_sequence, _journalNumber);
 
   UPDATE checkhead
index be98b98..71a87e2 100644 (file)
@@ -1,11 +1,10 @@
 SELECT dropIfExists('FUNCTION', 'postCountTag(integer, boolean, text)', 'public');
 
-CREATE OR REPLACE FUNCTION postCountTag(INTEGER, BOOLEAN) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION postCountTag(pInvcntid INTEGER,
+                                        pThaw BOOLEAN) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pInvcntid ALIAS FOR $1;
-  pThaw ALIAS FOR $2;
   _avgCostingMethod TEXT;
   _invhistid INTEGER;
   _postDate TIMESTAMP;
@@ -243,8 +242,8 @@ BEGIN
 --  Avoid negative value when average cost item
     UPDATE itemsite
     SET itemsite_qtyonhand=_p.invcnt_qoh_after,
-        itemsite_nnqoh = 0,
-        itemsite_value = CASE WHEN ((itemsite_costmethod='A') AND (_p.itemsite_value + (_p.cost * (_p.invcnt_qoh_after - itemsite_qtyonhand))) < 0.0) THEN 0.0
+        itemsite_value = CASE WHEN ((itemsite_costmethod='A') AND
+                                    (_p.itemsite_value + (_p.cost * (_p.invcnt_qoh_after - itemsite_qtyonhand))) < 0.0) THEN 0.0
                               ELSE (_p.itemsite_value + (_p.cost * (_p.invcnt_qoh_after - itemsite_qtyonhand)))
                          END,
         itemsite_datelastcount=_postDate
@@ -263,7 +262,8 @@ BEGIN
     END IF;
 
 --  Distribute to G/L
-    PERFORM insertGLTransaction( 'I/M', 'CT', _p.invcnt_tagnumber, ('Post Count Tag #' || _p.invcnt_tagnumber || ' for Item ' || _p.item_number),
+    PERFORM insertGLTransaction( 'I/M', 'CT', _p.invcnt_tagnumber,
+                                 ('Post Count Tag #' || _p.invcnt_tagnumber || ' for Item ' || _p.item_number),
                                  costcat_adjustment_accnt_id, costcat_asset_accnt_id, _invhistid,
                                  ( (_p.invcnt_qoh_after - _p.itemsite_qtyonhand) * _p.cost), _postDate::DATE )
     FROM invcnt, itemsite, costcat
@@ -278,4 +278,4 @@ BEGIN
   END IF;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 94514b8..aaa0cd7 100644 (file)
@@ -1,9 +1,8 @@
-CREATE OR REPLACE FUNCTION postCountTagLocation(INTEGER, BOOLEAN) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION postCountTagLocation(pInvcntid INTEGER,
+                                                pThaw BOOLEAN) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pInvcntid ALIAS FOR $1;
-  pThaw ALIAS FOR $2;
   _avgCostingMethod TEXT;
   _invhistid INTEGER;
   _postDate TIMESTAMP;
@@ -15,7 +14,6 @@ DECLARE
   _itemloc RECORD;
   _cntslip RECORD;
   _origLocQty NUMERIC;
-  _netable BOOLEAN;
   _lsid INTEGER;
 BEGIN
 
@@ -29,7 +27,7 @@ BEGIN
          itemsite_loccntrl, COALESCE(invcnt_location_id, -1) AS itemsite_location_id,
          CASE WHEN (itemsite_costmethod = 'N') THEN 0
               WHEN ( (itemsite_costmethod = 'A') AND
-                     ((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND
+                     (itemsite_qtyonhand = 0.0) AND
                      (_avgCostingMethod = 'ACT') ) THEN actcost(itemsite_item_id)
               WHEN ( (itemsite_costmethod = 'A') AND
                      (_avgCostingMethod IN ('ACT', 'AVG')) ) THEN avgcost(itemsite_id)
@@ -46,15 +44,12 @@ BEGIN
     RETURN -9;
   END IF;
 
-  SELECT COALESCE(SUM(itemloc_qty),0.0), location_netable INTO _origLocQty,_netable
-    FROM itemloc,location
+  SELECT COALESCE(SUM(itemloc_qty),0.0) INTO _origLocQty
+    FROM itemloc
    WHERE ((itemloc_itemsite_id=_p.itemsite_id)
-     AND  (location_id=itemloc_location_id)
-     AND  (itemloc_location_id=_p.invcnt_location_id))
-   GROUP BY location_netable;
+     AND  (itemloc_location_id=_p.invcnt_location_id));
   IF (NOT FOUND) THEN
     _origLocQty := 0.0;
-    _netable := TRUE;
   END IF;
 
   SELECT NEXTVAL('invhist_invhist_id_seq') INTO _invhistid;
@@ -236,23 +231,13 @@ BEGIN
    AND (invcnt_id=pInvcntid) );
 
 --  Update the QOH
-  IF (_netable) THEN
-    UPDATE itemsite
-    SET itemsite_qtyonhand= itemsite_qtyonhand + (_p.invcnt_qoh_after - _origLocQty),
-        itemsite_datelastcount=_postDate
-    WHERE (itemsite_id=_p.itemsite_id);
-    UPDATE itemsite
-    SET itemsite_value =  (itemsite_qtyonhand + itemsite_nnqoh) * _p.cost
-    WHERE (itemsite_id=_p.itemsite_id);
-  ELSE
-    UPDATE itemsite
-    SET itemsite_nnqoh =  itemsite_nnqoh + (_p.invcnt_qoh_after - _origLocQty),
-        itemsite_datelastcount=_postDate
-    WHERE (itemsite_id=_p.itemsite_id);
-    UPDATE itemsite
-    SET itemsite_value =  (itemsite_qtyonhand + itemsite_nnqoh) * _p.cost
-    WHERE (itemsite_id=_p.itemsite_id);
-  END IF;
+  UPDATE itemsite
+  SET itemsite_qtyonhand= itemsite_qtyonhand + (_p.invcnt_qoh_after - _origLocQty),
+      itemsite_datelastcount=_postDate
+  WHERE (itemsite_id=_p.itemsite_id);
+  UPDATE itemsite
+  SET itemsite_value =  itemsite_qtyonhand * _p.cost
+  WHERE (itemsite_id=_p.itemsite_id);
  
 --  Post the detail, if any
   IF (_hasDetail) THEN
@@ -267,7 +252,8 @@ BEGIN
   END IF;
 
 --  Distribute to G/L
-  PERFORM insertGLTransaction( 'I/M', 'CT', _p.invcnt_tagnumber, ('Post Count Tag #' || _p.invcnt_tagnumber || ' for Item ' || _p.item_number),
+  PERFORM insertGLTransaction( 'I/M', 'CT', _p.invcnt_tagnumber,
+                               ('Post Count Tag #' || _p.invcnt_tagnumber || ' for Item ' || _p.item_number),
                                costcat_adjustment_accnt_id, costcat_asset_accnt_id, _invhistid,
                                ( (_p.invcnt_qoh_after - _origLocQty) * _p.cost), CURRENT_DATE )
   FROM invcnt, itemsite, costcat
@@ -277,4 +263,4 @@ BEGIN
 
   RETURN 0;
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 9afe786..46f272f 100644 (file)
@@ -127,7 +127,7 @@ BEGIN
     (itemsite_qtyonhand + (_sense * pQty)),
     itemsite_costmethod, itemsite_value,
     -- sanity check to ensure that value = 0 when qtyonhand = 0
-    CASE WHEN ((itemsite_qtyonhand + (_sense * pQty)) + itemsite_nnqoh) = 0.0 THEN 0.0
+    CASE WHEN ((itemsite_qtyonhand + (_sense * pQty))) = 0.0 THEN 0.0
          ELSE itemsite_value + (_r.cost * _sense * pQty)
     END,
     pOrderType, pOrderNumber, pDocNumber, pComments,
diff --git a/foundation-database/public/functions/qtyatlocation.sql b/foundation-database/public/functions/qtyatlocation.sql
new file mode 100644 (file)
index 0000000..1c2ab13
--- /dev/null
@@ -0,0 +1,21 @@
+
+CREATE OR REPLACE FUNCTION qtyAtLocation(pItemsiteid INTEGER,
+                                         pLocationid INTEGER) RETURNS NUMERIC STABLE AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _qty         NUMERIC := 0.0;
+
+BEGIN
+  SELECT CASE WHEN (pLocationid IS NULL) THEN itemsite_qtyonhand
+              ELSE COALESCE(SUM(itemloc_qty), 0.0)
+         END INTO _qty
+    FROM itemsite LEFT OUTER JOIN itemloc ON (itemloc_itemsite_id=itemsite_id)
+   WHERE ((itemsite_id=pItemsiteid)
+     AND  (itemloc_location_id=pLocationid))
+  GROUP BY itemsite_qtyonhand;
+
+  RETURN _qty;
+
+END;
+$$ LANGUAGE plpgsql;
index 5ccbbea..2145d7b 100644 (file)
@@ -1,35 +1,78 @@
-CREATE OR REPLACE FUNCTION qtyAvailable(INTEGER, INTEGER) RETURNS NUMERIC AS '
+
+CREATE OR REPLACE FUNCTION qtyAvailable(pItemsiteId INTEGER) RETURNS NUMERIC STABLE AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _qty         NUMERIC = 0.0;
+
+BEGIN
+  _qty := qtyAvailable(pItemsiteId, TRUE);
+
+  RETURN _qty;
+
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION qtyAvailable(pItemsiteId INTEGER,
+                                        pUsable BOOLEAN) RETURNS NUMERIC STABLE AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _qty         NUMERIC = 0.0;
+
+BEGIN
+  IF (pUsable) THEN
+    -- Summarize itemloc qty for this itemsite/usable locations
+    -- or use itemsite_qtyonhand for regular/non-lot
+    SELECT COALESCE(SUM(itemloc_qty), itemsite_qtyonhand) INTO _qty
+      FROM itemsite LEFT OUTER JOIN itemloc ON (itemloc_itemsite_id=itemsite_id)
+                    LEFT OUTER JOIN location ON (location_id=itemloc_location_id)
+     WHERE (itemsite_id=pItemsiteId)
+       AND ((location_id IS NULL) OR (COALESCE(location_usable, true)))
+     GROUP BY itemsite_qtyonhand;
+  ELSE
+    -- Summarize itemloc qty for this itemsite/non-usable locations
+    SELECT COALESCE(SUM(itemloc_qty), 0.0) INTO _qty
+      FROM itemloc JOIN location ON (location_id=itemloc_location_id)
+     WHERE (itemloc_itemsite_id=pItemsiteId)
+       AND (NOT COALESCE(location_usable, true));
+  END IF;
+
+  RETURN _qty;
+
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION qtyAvailable(pItemsiteid INTEGER,
+                                        pLookAheadDays INTEGER) RETURNS NUMERIC STABLE AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
-  pLookAheadDays ALIAS FOR $2;
 
 BEGIN
 
-  RETURN ( ( SELECT itemsite_qtyonhand
+  RETURN ( ( SELECT qtyAvailable(itemsite_id)
              FROM itemsite
              WHERE (itemsite_id=pItemsiteid) ) +
            (SELECT qtyOrdered(pItemsiteid, pLookAheadDays)) -
            (SELECT qtyAllocated(pitemsiteid, pLookAheadDays)) );
 END;
-' LANGUAGE 'plpgsql' STABLE;
+$$ LANGUAGE plpgsql;
 
 
-CREATE OR REPLACE FUNCTION qtyAvailable(INTEGER, DATE) RETURNS NUMERIC AS '
+CREATE OR REPLACE FUNCTION qtyAvailable(pItemsiteid INTEGER,
+                                        pDate DATE) RETURNS NUMERIC STABLE AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
-  pDate ALIAS FOR $2;
 
 BEGIN
 
-  RETURN ( ( SELECT itemsite_qtyonhand
+  RETURN ( ( SELECT qtyAvailable(itemsite_id)
              FROM itemsite
              WHERE (itemsite_id=pItemsiteid) ) +
            (SELECT qtyOrdered(pItemsiteid, (pDate - CURRENT_DATE))) -
            (SELECT qtyAllocated(pItemsiteid, (pDate - CURRENT_DATE))) );
 END;
-' LANGUAGE 'plpgsql' STABLE;
+$$ LANGUAGE plpgsql;
 
diff --git a/foundation-database/public/functions/qtynetable.sql b/foundation-database/public/functions/qtynetable.sql
new file mode 100644 (file)
index 0000000..cb2a6fb
--- /dev/null
@@ -0,0 +1,44 @@
+
+CREATE OR REPLACE FUNCTION qtyNetable(pItemsiteId INTEGER) RETURNS NUMERIC STABLE AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _qty         NUMERIC = 0.0;
+
+BEGIN
+  _qty := qtyNetable(pItemsiteId, TRUE);
+
+  RETURN _qty;
+
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION qtyNetable(pItemsiteId INTEGER,
+                                      pNetable BOOLEAN) RETURNS NUMERIC STABLE AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _qty         NUMERIC = 0.0;
+
+BEGIN
+  IF (pNetable) THEN
+    -- Summarize itemloc qty for this itemsite/netable locations
+    -- or use itemsite_qtyonhand for regular/non-lot
+    SELECT COALESCE(SUM(itemloc_qty), itemsite_qtyonhand) INTO _qty
+      FROM itemsite LEFT OUTER JOIN itemloc ON (itemloc_itemsite_id=itemsite_id)
+                    LEFT OUTER JOIN location ON (location_id=itemloc_location_id)
+     WHERE (itemsite_id=pItemsiteId)
+       AND ((location_id IS NULL) OR (COALESCE(location_netable, true)))
+     GROUP BY itemsite_qtyonhand;
+  ELSE
+    -- Summarize itemloc qty for this itemsite/non-netable locations
+    SELECT COALESCE(SUM(itemloc_qty), 0.0) INTO _qty
+      FROM itemloc JOIN location ON (location_id=itemloc_location_id)
+     WHERE (itemloc_itemsite_id=pItemsiteId)
+       AND (NOT COALESCE(location_netable, true));
+  END IF;
+
+  RETURN _qty;
+
+END;
+$$ LANGUAGE plpgsql;
diff --git a/foundation-database/public/functions/releasepr.sql b/foundation-database/public/functions/releasepr.sql
new file mode 100644 (file)
index 0000000..f004415
--- /dev/null
@@ -0,0 +1,195 @@
+
+CREATE OR REPLACE FUNCTION releasePR(pPrId INTEGER) RETURNS INTEGER AS $$
+-- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
+-- See www.xtuple.com/CPAL for the full text of the software license.
+DECLARE
+  _pr RECORD;
+  _w RECORD;
+  _i RECORD;
+  _rows INTEGER := 0;
+  _itemsrcid INTEGER := -1;
+  _poheadid INTEGER := -1;
+  _poitemid INTEGER := -1;
+  _taxtypeid INTEGER := -1;
+  _polinenumber INTEGER;
+  _ponumber NUMERIC;
+  _price NUMERIC;
+
+BEGIN
+
+  -- Cache information
+  SELECT *,
+         CASE WHEN(pr_order_type='W') THEN pr_order_id
+              ELSE -1
+         END AS parentwo,
+         CASE WHEN(pr_order_type='S') THEN pr_order_id
+              ELSE -1
+         END AS parentso
+  INTO _pr
+  FROM pr LEFT OUTER JOIN itemsite ON (pr_itemsite_id = itemsite_id)
+          LEFT OUTER JOIN item ON (item_id = itemsite_item_id)
+          LEFT OUTER JOIN prj ON (prj_id = pr_prj_id)
+  WHERE (pr_id = pPrId);
+  IF (NOT FOUND) THEN
+    RETURN -1;
+  END IF;
+
+  SELECT * INTO _w
+  FROM itemsite JOIN whsinfo ON (warehous_id = itemsite_warehous_id)
+                LEFT OUTER JOIN addr ON (warehous_addr_id = addr_id)
+                LEFT OUTER JOIN cntct ON (warehous_cntct_id = cntct_id)
+  WHERE (itemsite_id = _pr.itemsite_id);
+
+  -- Must either be a single itemsrc or a default itemsrc
+  SELECT itemsrc_id INTO _itemsrcid
+  FROM itemsrc
+  WHERE (itemsrc_item_id = _pr.item_id)
+    AND (_pr.pr_duedate BETWEEN COALESCE(itemsrc_effective, startOfTime()) AND COALESCE(itemsrc_expires, endOfTime()))
+    AND (itemsrc_default);
+  IF (NOT FOUND) THEN
+    SELECT MAX(itemsrc_id), count(*) INTO _itemsrcid, _rows
+    FROM itemsrc
+    WHERE (itemsrc_item_id = _pr.item_id)
+      AND (_pr.pr_duedate BETWEEN COALESCE(itemsrc_effective, startOfTime()) AND COALESCE(itemsrc_expires, endOfTime()))
+    GROUP BY itemsrc_item_id;
+    IF (NOT FOUND) THEN
+      RETURN -2;
+    END IF;
+    IF (_rows > 1) THEN
+      RETURN -2;
+    END IF;
+  END IF;
+    
+  SELECT * INTO _i
+  FROM itemsrc JOIN vendinfo ON (itemsrc_vend_id = vend_id)
+               LEFT OUTER JOIN cntct ON (vend_cntct1_id = cntct_id)
+               LEFT OUTER JOIN addr ON (vend_addr_id = addr_id)
+  WHERE (itemsrc_id = _itemsrcid);
+
+  RAISE NOTICE 'releasepr selected itemsrc_id = % for pr = %', _itemsrcid, _pr.pr_id;
+
+  -- Find matching unreleased PO
+  SELECT COALESCE(pohead_id, -1) INTO _poheadid
+  FROM pohead
+  WHERE ( (pohead_status = 'U')
+    AND (pohead_vend_id = _i.itemsrc_vend_id)
+    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, '')) );
+
+  IF (NOT FOUND) THEN
+    -- Create new PO
+    SELECT NEXTVAL('pohead_pohead_id_seq') INTO _poheadid;
+    SELECT fetchPoNumber() INTO _ponumber;
+
+    INSERT INTO pohead
+      ( pohead_id, pohead_number, pohead_status, pohead_dropship,
+        pohead_agent_username, pohead_vend_id, pohead_taxzone_id,
+        pohead_orderdate, pohead_curr_id, pohead_cohead_id,
+        pohead_warehous_id, pohead_shipvia,
+        pohead_terms_id, pohead_shipto_cntct_id,
+        pohead_shipto_cntct_honorific, pohead_shipto_cntct_first_name,
+        pohead_shipto_cntct_middle, pohead_shipto_cntct_last_name,
+        pohead_shipto_cntct_suffix, pohead_shipto_cntct_phone,
+        pohead_shipto_cntct_title, pohead_shipto_cntct_fax, 
+        pohead_shipto_cntct_email, pohead_shiptoaddress_id,
+        pohead_shiptoaddress1,
+        pohead_shiptoaddress2,
+        pohead_shiptoaddress3,
+        pohead_shiptocity, 
+        pohead_shiptostate, pohead_shiptozipcode,
+        pohead_shiptocountry, pohead_vend_cntct_id,
+        pohead_vend_cntct_honorific, pohead_vend_cntct_first_name,
+        pohead_vend_cntct_middle, pohead_vend_cntct_last_name,
+        pohead_vend_cntct_suffix, pohead_vend_cntct_phone,
+        pohead_vend_cntct_title, pohead_vend_cntct_fax,
+        pohead_vend_cntct_email, pohead_vendaddress1,
+        pohead_vendaddress2, pohead_vendaddress3,
+        pohead_vendcity, pohead_vendstate,
+        pohead_vendzipcode, pohead_vendcountry )
+    VALUES
+      ( _poheadid, _ponumber, 'U', FALSE,
+        getEffectiveXtUser(), _i.itemsrc_vend_id, _i.vend_taxzone_id,
+        CURRENT_DATE, COALESCE(_i.vend_curr_id, basecurrid()), NULL,
+        COALESCE(_pr.itemsite_warehous_id, -1), COALESCE(_i.vend_shipvia, TEXT('')),
+        COALESCE(_i.vend_terms_id, -1), _w.cntct_id,
+        _w.cntct_honorific, _w.cntct_first_name,
+        _w.cntct_middle, _w.cntct_last_name,
+        _w.cntct_suffix, _w.cntct_phone,
+        _w.cntct_title, _w.cntct_fax,
+        _w.cntct_email, _w.addr_id,
+        COALESCE(_w.addr_line1, ''),
+        COALESCE(_w.addr_line2, ''),
+        COALESCE(_w.addr_line3, ''),
+        COALESCE(_w.addr_city, ''),
+        COALESCE(_w.addr_state, ''), COALESCE(_w.addr_postalcode, ''),
+        COALESCE(_w.addr_country, ''), _i.cntct_id,
+        COALESCE(_i.cntct_honorific, TEXT('')), COALESCE(_i.cntct_first_name, TEXT('')),
+        COALESCE(_i.cntct_middle, TEXT('')), COALESCE(_i.cntct_last_name, TEXT('')),
+        COALESCE(_i.cntct_suffix, TEXT('')), COALESCE(_i.cntct_phone, TEXT('')),
+        COALESCE(_i.cntct_title, TEXT('')), COALESCE(_i.cntct_fax, TEXT('')),
+        COALESCE(_i.cntct_email, TEXT('')), COALESCE(_i.addr_line1, TEXT('')),
+        COALESCE(_i.addr_line2, TEXT('')), COALESCE(_i.addr_line3, TEXT('')),
+        COALESCE(_i.addr_city, TEXT('')), COALESCE(_i.addr_state, TEXT('')),
+        COALESCE(_i.addr_postalcode, TEXT('')), COALESCE(_i.addr_country, TEXT('')) );
+  END IF;
+
+  SELECT NEXTVAL('poitem_poitem_id_seq') INTO _poitemid;
+
+  SELECT (COALESCE(MAX(poitem_linenumber), 0) + 1) INTO _polinenumber
+  FROM poitem
+  WHERE (poitem_pohead_id = _poheadid);
+
+  SELECT COALESCE(itemtax_taxtype_id, -1) INTO _taxtypeid
+  FROM itemtax
+  WHERE (itemtax_item_id = _i.itemsrc_item_id);
+
+  SELECT itemsrcPrice(_i.itemsrc_id,
+                      COALESCE(_pr.itemsite_warehous_id, -1),
+                      FALSE,
+                      (_pr.pr_qtyreq / COALESCE(_i.itemsrc_invvendoruomratio, 1.00)),
+                      COALESCE(_i.vend_curr_id, baseCurrId()),
+                      CURRENT_DATE) INTO _price;
+
+  -- Create PO Item
+  INSERT INTO poitem
+    ( poitem_id, poitem_status, poitem_pohead_id, poitem_linenumber, 
+      poitem_duedate, poitem_itemsite_id,
+      poitem_vend_item_descrip, poitem_vend_uom,
+      poitem_invvenduomratio, poitem_qty_ordered, 
+      poitem_unitprice, poitem_vend_item_number, 
+      poitem_itemsrc_id, poitem_order_id, poitem_order_type, poitem_prj_id, poitem_stdcost, 
+      poitem_manuf_name, poitem_manuf_item_number, 
+      poitem_manuf_item_descrip, poitem_taxtype_id, poitem_comments )
+  VALUES
+    ( _poitemid, 'U', _poheadid, _polinenumber,
+      _pr.pr_duedate, _pr.itemsite_id,
+      COALESCE(_i.itemsrc_vend_item_descrip, TEXT('')), COALESCE(_i.itemsrc_vend_uom, TEXT('')),
+      COALESCE(_i.itemsrc_invvendoruomratio, 1.00), (_pr.pr_qtyreq / COALESCE(_i.itemsrc_invvendoruomratio, 1.00)),
+      _price, COALESCE(_i.itemsrc_vend_item_number, TEXT('')),
+      _i.itemsrc_id, _pr.pr_order_id, _pr.pr_order_type, _pr.prj_id, stdcost(_i.itemsrc_item_id),
+      COALESCE(_i.itemsrc_manuf_name, TEXT('')), COALESCE(_i.itemsrc_manuf_item_number, TEXT('')),
+      COALESCE(_i.itemsrc_manuf_item_descrip, TEXT('')), _taxtypeid,
+      COALESCE(_pr.pr_releasenote, TEXT('')));
+
+  -- Copy characteristics from the pr to the poitem
+  INSERT INTO charass
+    ( charass_target_type, charass_target_id, charass_char_id,
+      charass_value, charass_default, charass_price )
+  SELECT 'PI', _poitemid, charass_char_id,
+         charass_value, charass_default, charass_price
+  FROM charass
+  WHERE ( (charass_target_type='PR')
+    AND   (charass_target_id=pPrId) );
+
+  -- Delete the PR
+  PERFORM deletePr(pPrId);
+
+  RETURN _poitemid;
+
+END;
+$$ LANGUAGE 'plpgsql' VOLATILE;
index 29823d9..719091a 100644 (file)
@@ -4,18 +4,18 @@ CREATE OR REPLACE FUNCTION relocateInventory(INTEGER, INTEGER, INTEGER, NUMERIC,
 BEGIN
   RETURN relocateInventory($1, $2, $3, $4, $5, CURRENT_TIMESTAMP);
 END;
-$$ LANGUAGE 'plpgsql';
-
-CREATE OR REPLACE FUNCTION relocateInventory(INTEGER, INTEGER, INTEGER, NUMERIC, TEXT, TIMESTAMP WITH TIME ZONE) RETURNS INTEGER AS $$
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION relocateInventory(pSourceItemlocid INTEGER,
+                                             pTargetLocationid INTEGER,
+                                             pItemsiteid INTEGER,
+                                             pQty NUMERIC,
+                                             pComments TEXT,
+                                             pGLDistTS TIMESTAMP WITH TIME ZONE) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pSourceItemlocid      ALIAS FOR $1;
-  pTargetLocationid     ALIAS FOR $2;
-  pItemsiteid           ALIAS FOR $3;
-  pQty                  ALIAS FOR $4;
-  pComments             ALIAS FOR $5;
-  _GlDistTS             TIMESTAMP WITH TIME ZONE := $6;
+  _GlDistTS             TIMESTAMP WITH TIME ZONE;
   _targetItemlocid      INTEGER;
   _invhistid            INTEGER;
   _p                    RECORD;
@@ -28,8 +28,10 @@ DECLARE
 
 BEGIN
 
-    IF ((_GlDistTS IS NULL) OR (CAST(_GlDistTS AS date)=CURRENT_DATE)) THEN
+    IF ((pGlDistTS IS NULL) OR (CAST(pGlDistTS AS date)=CURRENT_DATE)) THEN
       _GlDistTS := CURRENT_TIMESTAMP;
+    ELSE
+      _GLDistTS := pGLDistTS;
     END IF;
 
 --  Make sure the passed itemsite points to a real item
@@ -45,13 +47,9 @@ BEGIN
          itemloc_itemsite_id AS itemsiteid,
          itemloc_expiration,
          itemloc_warrpurc,
-         itemloc_qty,
-         sourceloc.location_netable AS sourcenet,
-         targetloc.location_netable AS targetnet INTO _p
-  FROM itemloc, location AS sourceloc, location AS targetloc
-  WHERE ( (itemloc_location_id=sourceloc.location_id)
-   AND (targetloc.location_id=pTargetLocationid)
-   AND (itemloc_id=pSourceItemlocid) );
+         itemloc_qty INTO _p
+  FROM itemloc
+  WHERE (itemloc_id=pSourceItemlocid);
 
 --  Check to make sure the qty being transfered exists
   IF (_p.itemloc_qty < pQty) THEN
@@ -141,42 +139,6 @@ BEGIN
   SET invhist_hasdetail=TRUE
   WHERE (invhist_id=_invhistid);
 
---  Post in incomming or outgoing NN transaction if required
-  IF (_p.sourcenet <> _p.targetnet) THEN
-    IF (_p.targetnet) THEN
-      _qty = (pQty * -1);
-    ELSE
-      _qty = pQty;
-    END IF;
-
-    INSERT INTO invhist
-    ( invhist_itemsite_id,
-      invhist_transtype, invhist_invqty,
-      invhist_qoh_before, invhist_qoh_after,
-      invhist_docnumber, invhist_comments, invhist_transdate,
-      invhist_invuom, invhist_unitcost, invhist_costmethod,
-      invhist_value_before, invhist_value_after, invhist_series) 
-    SELECT itemsite_id,
-           'NN', (_qty * -1),
-           itemsite_qtyonhand, (itemsite_qtyonhand - _qty),
-           '', '', _GlDistTS,
-           uom_name,
-           CASE WHEN (itemsite_costmethod='A') THEN avgcost(itemsite_id)
-                ELSE stdCost(item_id)
-           END, itemsite_costmethod,
-           itemsite_value, itemsite_value, _itemlocSeries
-    FROM item, itemsite, uom
-    WHERE ( (itemsite_item_id=item_id)
-     ANd (item_inv_uom_id=uom_id)
-     AND (itemsite_controlmethod <> 'N')
-     AND (itemsite_id=_p.itemsiteid) );
-
-    UPDATE itemsite
-    SET itemsite_qtyonhand = (itemsite_qtyonhand - _qty),
-        itemsite_nnqoh = (itemsite_nnqoh + _qty)
-    WHERE (itemsite_id=_p.itemsiteid);
-  END IF;
-
 --  Check to see if there is anything left at the target Itemloc and delete if not
 --  Could be zero if relocate increased a negative quantity to zero
   DELETE FROM itemloc
@@ -237,4 +199,4 @@ BEGIN
   RETURN _invhistid;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index 7ee2ad6..2887dcd 100644 (file)
@@ -1,304 +1,8 @@
-
-CREATE OR REPLACE FUNCTION reopenBankReconciliation(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION reopenBankReconciliation(pBankrecid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
-DECLARE
-  pBankrecid ALIAS FOR $1;
-  _bankrecid INTEGER;
-  _accntid INTEGER;
-  _sequence INTEGER;
-  _gltransid INTEGER;
-  _result INTEGER;
-  _r RECORD;
-  _tax RECORD;
-
 BEGIN
-
--- Check the accnt information to make sure it is valid
-  SELECT accnt_id INTO _accntid
-    FROM bankrec, bankaccnt, accnt
-   WHERE ( (bankaccnt_accnt_id=accnt_id)
-     AND   (bankrec_bankaccnt_id=bankaccnt_id)
-     AND   (bankrec_id=pBankrecid) );
-  IF ( NOT FOUND ) THEN
-    RETURN -1;
-  END IF;
-
-  SELECT bankrec_id INTO _bankrecid
-    FROM bankrec
-   WHERE (NOT bankrec_posted);
-  IF (FOUND) THEN
-  -- Delete any bankrecitem records for unposted periods
-    DELETE FROM bankrecitem
-     WHERE (bankrecitem_bankrec_id=_bankrecid);
-  -- Delete any bankrec records for unposted period
-    DELETE FROM bankrec
-     WHERE (bankrec_id=_bankrecid);
-  END IF;
-
-  IF (fetchMetricBool('CashBasedTax')) THEN
-    -- Cash based tax distributions
-    -- GL Transactions
-    SELECT fetchGLSequence() INTO _sequence;
-    FOR _r IN SELECT *
-              FROM bankrecitem
-             WHERE ( (bankrecitem_cleared)
-               AND   (bankrecitem_bankrec_id=pBankrecid) ) LOOP
-      -- first, debit the tax liability clearing account
-      -- and credit the tax liability distribution account
-      -- for each tax code
-      FOR _tax IN SELECT docnumber, custname, distdate, source, doctype,
-                         tax_sales_accnt_id, tax_dist_accnt_id,
-                         ROUND(currToBase(currid, ROUND(SUM(taxhist_tax),2), taxhist_docdate) * percentpaid, 2) AS taxbasevalue
-                  FROM (
-                        -- Cash receipt, gltrans
-                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
-                               aropen_curr_id AS currid, gltrans_date AS distdate,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
-                                                    AND (gltrans_doctype='CR')
-                                                    AND (gltrans_misc_id=cashrcpt_id))
-                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                     JOIN custinfo ON (cust_id=aropen_cust_id)
-                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash receipt, sltrans
-                        UNION
-                        SELECT aropen_docnumber AS docnumber, cust_name AS custname,
-                               aropen_curr_id AS currid, sltrans_date AS distdate,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
-                                                    AND (sltrans_doctype='CR')
-                                                    AND (sltrans_misc_id=cashrcpt_id))
-                                     JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                     JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                     JOIN custinfo ON (cust_id=aropen_cust_id)
-                                     JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                     JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, gltrans
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, gltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
-                                                    AND (gltrans_doctype='CK')
-                                                    AND (gltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, gltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               gltrans_source AS source, gltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM gltrans JOIN checkhead ON ((gltrans_source='A/P')
-                                                    AND (gltrans_doctype='CK')
-                                                    AND (gltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, sltrans
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, sltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
-                                                    AND (sltrans_doctype='CK')
-                                                    AND (sltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT apopen_docnumber AS docnumber, vend_name AS vendname,
-                               apopen_curr_id AS currid, sltrans_date AS distdate,
-                               (vohead_amount / apopen_amount) AS percentpaid,
-                               sltrans_source AS source, sltrans_doctype AS doctype,
-                               tax_sales_accnt_id, tax_dist_accnt_id,
-                               taxhist_tax, taxhist_docdate
-                        FROM sltrans JOIN checkhead ON ((sltrans_source='A/P')
-                                                    AND (sltrans_doctype='CK')
-                                                    AND (sltrans_misc_id=checkhead_id))
-                                     JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                     JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                     JOIN vohead ON (vohead_number=apopen_docnumber)
-                                     JOIN vendinfo ON (vend_id=apopen_vend_id)
-                                     JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                     JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                                     JOIN tax ON (tax_id=taxhist_tax_id)
-                        WHERE (sltrans_id=_r.bankrecitem_source_id)
-                       ) AS data
-                  GROUP BY docnumber, custname, currid, distdate, percentpaid,
-                           source, doctype,
-                           tax_sales_accnt_id, tax_dist_accnt_id, taxhist_docdate
-      LOOP
-        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
-                                   _tax.tax_dist_accnt_id, 
-                                   (_tax.taxbasevalue * -1.0),
-                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
-        IF (_result < 0) THEN
-          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
-        END IF;
-        SELECT insertIntoGLSeries( _sequence, _tax.source, _tax.doctype, _tax.docnumber,
-                                   _tax.tax_sales_accnt_id, 
-                                   _tax.taxbasevalue,
-                                   COALESCE(_r.bankrecitem_effdate, _tax.distdate), _tax.custname ) INTO _result;
-        IF (_result < 0) THEN
-          RAISE EXCEPTION 'insertIntoGLSeries failed, result=%', _result;
-        END IF;
-      END LOOP;
-
-      -- second, create a taxpay row for each taxhist
-      FOR _tax IN SELECT taxhist_id, applyid, distdate,
-                         ROUND(taxhist_tax * percentpaid, 2) AS taxpaid
-                  FROM (
-                        -- Cash receipt, gltrans
-                        SELECT taxhist_id, aropen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid
-                          FROM gltrans JOIN cashrcpt  ON ((gltrans_source='A/R')
-                                                      AND (gltrans_doctype='CR')
-                                                      AND (gltrans_misc_id=cashrcpt_id))
-                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash receipt, sltrans
-                        UNION
-                        SELECT taxhist_id, aropen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (cashrcptitem_amount / aropen_amount) AS percentpaid
-                          FROM sltrans JOIN cashrcpt  ON ((sltrans_source='A/R')
-                                                      AND (sltrans_doctype='CR')
-                                                      AND (sltrans_misc_id=cashrcpt_id))
-                                       JOIN cashrcptitem ON (cashrcptitem_cashrcpt_id=cashrcpt_id)
-                                       JOIN aropen ON (aropen_id=cashrcptitem_aropen_id)
-                                       JOIN cohist ON (cohist_invcnumber=aropen_docnumber AND cohist_doctype=aropen_doctype)
-                                       JOIN cohisttax ON (taxhist_parent_id=cohist_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, gltrans
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
-                                                       AND (gltrans_doctype='CK')
-                                                       AND (gltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, gltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM gltrans JOIN checkhead  ON ((gltrans_source='A/P')
-                                                       AND (gltrans_doctype='CK')
-                                                       AND (gltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                          WHERE (gltrans_id=_r.bankrecitem_source_id)
-                        -- Cash payment, sltrans
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
-                                                       AND (sltrans_doctype='CK')
-                                                       AND (sltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voheadtax ON (taxhist_parent_id=vohead_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                        UNION
-                        SELECT taxhist_id, apopen_id AS applyid, sltrans_date AS distdate, taxhist_tax,
-                               (checkitem_amount / apopen_amount) AS percentpaid
-                          FROM sltrans JOIN checkhead  ON ((sltrans_source='A/P')
-                                                       AND (sltrans_doctype='CK')
-                                                       AND (sltrans_misc_id=checkhead_id))
-                                       JOIN checkitem ON (checkitem_checkhead_id=checkhead_id)
-                                       JOIN apopen ON (apopen_id=checkitem_apopen_id)
-                                       JOIN vohead ON (vohead_number=apopen_docnumber)
-                                       JOIN voitem ON (voitem_vohead_id=vohead_id)
-                                       JOIN voitemtax ON (taxhist_parent_id=voitem_id)
-                          WHERE (sltrans_id=_r.bankrecitem_source_id)
-                       ) AS data
-      LOOP
-        DELETE FROM taxpay
-        WHERE (taxpay_taxhist_id=_tax.taxhist_id)
-          AND (taxpay_apply_id=_tax.applyid)
-          AND (taxpay_distdate=COALESCE(_r.bankrecitem_effdate, _tax.distdate))
-          AND (taxpay_tax=_tax.taxpaid);
-      END LOOP;
-
-    END LOOP;
-
-    SELECT postGLSeries(_sequence, fetchJournalNumber('GL-MISC')) INTO _result;
-    IF (_result < 0) THEN
-      RAISE EXCEPTION 'postGLSeries failed, result=%', _result;
-    END IF;
-
-  END IF;
-
--- Mark all the gltrans items that have been cleared as unreconciled.
-  UPDATE gltrans
-     SET gltrans_rec = FALSE
-   WHERE ( (gltrans_id IN (SELECT bankrecitem_source_id
-                             FROM bankrecitem
-                            WHERE ((bankrecitem_source = 'GL')
-                              AND  (bankrecitem_cleared)
-                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
-     AND   (gltrans_accnt_id=_accntid) ) ;
-
--- Mark all the sltrans items that have been cleared as unreconciled.
-  UPDATE sltrans
-     SET sltrans_rec = FALSE
-   WHERE ( (sltrans_id IN (SELECT bankrecitem_source_id
-                             FROM bankrecitem
-                            WHERE ((bankrecitem_source = 'SL')
-                              AND  (bankrecitem_cleared)
-                              AND  (bankrecitem_bankrec_id=pBankrecid) ) ) )
-     AND   (sltrans_accnt_id=_accntid) ) ;
-
--- Mark the bankrec record as unposted
-  UPDATE bankrec SET 
-    bankrec_posted = FALSE,
-    bankrec_postdate = NULL
-   WHERE (bankrec_id=pBankrecid);
-
-  RETURN pBankrecid;
+  RETURN bankReconciliation(pBankrecid, 'reopen');
 END;
 $$ LANGUAGE 'plpgsql';
 
index a04b21a..fc07e30 100644 (file)
@@ -1,19 +1,34 @@
 
-CREATE OR REPLACE FUNCTION setNextCheckNumber(INTEGER, INTEGER) RETURNS BOOLEAN AS '
+CREATE OR REPLACE FUNCTION setNextCheckNumber(pBankaccntid INTEGER,
+                                              pNextCheckNumber INTEGER) RETURNS BOOLEAN AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pBankaccntid ALIAS FOR $1;
-  pNextCheckNumber ALIAS FOR $2;
+  _nextChkNumber INTEGER;
+  _checkheadid INTEGER;
 
 BEGIN
 
+  _nextChkNumber := pNextCheckNumber;
+
+  WHILE (TRUE) LOOP
+    SELECT checkhead_id INTO _checkheadid
+    FROM checkhead
+    WHERE (checkhead_number=_nextChkNumber)
+      AND (checkhead_bankaccnt_id=pBankaccntid);
+    IF (NOT FOUND) THEN
+      EXIT;
+    ELSE
+      _nextChkNumber := _nextChkNumber + 1;
+    END IF;
+  END LOOP;
+
   UPDATE bankaccnt
-  SET bankaccnt_nextchknum=pNextCheckNumber
+  SET bankaccnt_nextchknum=_nextChkNumber
   WHERE (bankaccnt_id=pBankaccntid);
 
   RETURN TRUE;
 
 END;
-' LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
index 5bf833a..14280db 100644 (file)
@@ -37,7 +37,7 @@ BEGIN
                      noNeg(coitem_qtyord - coitem_qtyshipped +
                            coitem_qtyreturned - qtyAtShipping(pordertype, coitem_id)
                           ))) - coitem_qtyreserved) * coitem_qty_invuomratio
-                     ) <= itemsite_qtyonhand)
+                     ) <= qtyAvailable(itemsite_id))
               AND 
              (((COALESCE(pqty, roundQty(item_fractional,
                      noNeg(coitem_qtyord - coitem_qtyshipped +
@@ -57,7 +57,7 @@ BEGIN
                                      coitem_qtyreturned - qtyAtShipping(pordertype, coitem_id) - coitem_qtyreserved
                                      ) * coitem_qty_invuomratio
                      )
-              ) <= itemsite_qtyonhand)
+              ) <= qtyAvailable(itemsite_id))
         INTO _isqtyavail
         FROM coitem, itemsite, item
        WHERE ((coitem_itemsite_id=itemsite_id) 
@@ -72,7 +72,7 @@ BEGIN
                                    qtyAtShipping(pordertype, toitem_id)
                                    )
                    )
-           ) <= itemsite_qtyonhand) INTO _isqtyavail  
+           ) <= qtyAvailable(itemsite_id)) INTO _isqtyavail  
       FROM toitem, tohead, itemsite, item
      WHERE ((toitem_tohead_id=tohead_id)
        AND  (tohead_src_warehous_id=itemsite_warehous_id) 
index 54d85bc..ff36aba 100644 (file)
@@ -1,11 +1,8 @@
-CREATE OR REPLACE FUNCTION thawItemSite(INTEGER) RETURNS INTEGER AS $$
+CREATE OR REPLACE FUNCTION thawItemSite(pItemsiteid INTEGER) RETURNS INTEGER AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-  pItemsiteid ALIAS FOR $1;
   _qoh            NUMERIC := 0;
-  _netable_qoh    NUMERIC := 0;
-  _nonnetable_qoh NUMERIC := 0;
   _value          NUMERIC := 0;
   _itemlocid INTEGER;
   _itemloc RECORD;
@@ -48,9 +45,9 @@ BEGIN
 
 --  Cache the initial qty of the itemloc specified by the
 --  itemsite/location/lot/serial
-        SELECT itemloc_id, itemloc_qty, COALESCE(location_netable, TRUE) AS location_netable
+        SELECT itemloc_id, itemloc_qty
         INTO _itemloc
-        FROM itemloc LEFT OUTER JOIN location ON (location_id=itemloc_location_id)
+        FROM itemloc
         WHERE ( (itemloc_itemsite_id=pItemsiteid)
          AND (itemloc_location_id=_coarse.invdetail_location_id)
          AND (COALESCE(itemloc_ls_id,-1)=COALESCE(_coarse.invdetail_ls_id,-1))
@@ -70,17 +67,10 @@ BEGIN
             0, endOfTime() );
 
         _qoh := 0.0;
-        _netable_qoh := 0.0;
-        _nonnetable_qoh := 0.0;
 
         ELSE
           _itemlocid := _itemloc.itemloc_id;
           _qoh := _itemloc.itemloc_qty;
-          IF (_itemloc.location_netable) THEN
-            _netable_qoh := _itemloc.itemloc_qty;
-          ELSE
-            _nonnetable_qoh := _itemloc.itemloc_qty;
-          END IF;
         END IF;
 
 --  Now step through each unposted invdetail record for a given
@@ -104,11 +94,6 @@ BEGIN
 
 --  Update the running qoh
           _qoh = (_qoh + _fine.invdetail_qty);
-          IF (_itemloc.location_netable) THEN
-            _netable_qoh := (_netable_qoh + _fine.invdetail_qty);
-          ELSE
-            _nonnetable_qoh := (_nonnetable_qoh + _fine.invdetail_qty);
-          END IF;
 
         END LOOP;
 
@@ -166,11 +151,8 @@ BEGIN
 
     END LOOP;
 
--- _qoh can be used for the netable qoh because of the negative NN transactions
--- change to update qtyonhand with _netable_qoh
     UPDATE itemsite
-       SET itemsite_qtyonhand = _netable_qoh,
-           itemsite_nnqoh = _nonnetable_qoh,
+       SET itemsite_qtyonhand = _qoh,
            itemsite_value = CASE WHEN ((itemsite_costmethod='A') AND (_value < 0.0)) THEN 0.0
                                  ELSE _value END
      WHERE(itemsite_id=pItemsiteid);
@@ -180,4 +162,4 @@ BEGIN
   RETURN pItemsiteid;
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index c591b02..30fd3eb 100644 (file)
@@ -1,14 +1,17 @@
+SELECT dropIfExists('FUNCTION', 'toggleBankrecCleared(int,text,int)', 'public');
 
-CREATE OR REPLACE FUNCTION toggleBankrecCleared(INTEGER, TEXT, INTEGER) RETURNS BOOLEAN AS $$
+CREATE OR REPLACE FUNCTION toggleBankrecCleared(INTEGER, TEXT, INTEGER, NUMERIC, NUMERIC) RETURNS BOOLEAN AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
   pBankrecid ALIAS FOR $1;
   pSource    ALIAS FOR $2;
   pSourceid  ALIAS FOR $3;
+  pCurrrate  ALIAS FOR $4;
+  pAmount    ALIAS FOR $5;
 
 BEGIN
-  RETURN toggleBankrecCleared(pBankrecid, pSource, pSourceid, NULL, NULL, NULL);
+  RETURN toggleBankrecCleared(pBankrecid, pSource, pSourceid, pCurrrate, pAmount, NULL);
 END;
 $$ LANGUAGE 'plpgsql';
 
index 1beee66..4eff4ea 100644 (file)
@@ -1,12 +1,11 @@
-CREATE OR REPLACE FUNCTION updateStdCost(INTEGER, NUMERIC, NUMERIC, TEXT, TEXT) RETURNS BOOLEAN AS $$
+CREATE OR REPLACE FUNCTION updateStdCost(pItemcostid INTEGER,
+                                         pNewcost NUMERIC,
+                                         pOldcost NUMERIC,
+                                         pDocNumber TEXT,
+                                         pNotes TEXT) RETURNS BOOLEAN AS $$
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
 -- See www.xtuple.com/CPAL for the full text of the software license.
 DECLARE
-    pItemcostid        ALIAS FOR $1;
-    pNewcost   ALIAS FOR $2;
-    pOldcost   ALIAS FOR $3;
-    pDocNumber ALIAS FOR $4;
-    pNotes     ALIAS FOR $5;
     _itemcostid        INTEGER;
     _r         RECORD;
     _newcost   NUMERIC;
@@ -32,14 +31,14 @@ BEGIN
   END IF;
 
 --  Distribute to G/L, debit Inventory Asset, credit Inventory Cost Variance
-  FOR _r IN SELECT itemsite_id, (itemsite_qtyonhand + itemsite_nnqoh) AS totalQty,
+  FOR _r IN SELECT itemsite_id, itemsite_qtyonhand AS totalQty,
                    costcat_invcost_accnt_id, costcat_asset_accnt_id,
                    itemsite_costmethod
             FROM itemcost, itemsite, costcat
             WHERE ( (itemsite_item_id=itemcost_item_id)
              AND (itemsite_costcat_id=costcat_id)
              AND (itemsite_costmethod != 'A')
-             AND ((itemsite_qtyonhand + itemsite_nnqoh) <> 0)
+             AND (itemsite_qtyonhand <> 0.0)
              AND (itemcost_id=pItemcostid) ) LOOP
 --    IF (_newcost <> _oldcost) THEN
 --      RAISE NOTICE 'itemcost_id = %, Qty = %, Old Cost = %, New Cost = %', pItemcostid, _r.totalQty, _oldcost, _newcost;
@@ -153,4 +152,4 @@ BEGIN
 
     RETURN -1;
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
index b62f972..52bfd39 100644 (file)
@@ -46,7 +46,7 @@ BEGIN
                 item_descrip1, 
                 item_descrip2, 
                 uom_name,
-                noNeg(itemsite_qtyonhand) AS qoh, 
+                noNeg(qtyAvailable(itemsite_id)) AS qoh, 
                 noNeg(wo_qtyord - wo_qtyrcv) AS wobalance, 
                 qtyAllocated(itemsite_id, wo_duedate) AS allocated, 
                 qtyOrdered(itemsite_id, wo_duedate) AS ordered,                        
@@ -113,7 +113,7 @@ BEGIN
                         item_descrip1, 
                         item_descrip2, 
                         uom_name,                         
-                        noNeg(itemsite_qtyonhand) AS qoh, 
+                        noNeg(qtyAvailable(itemsite_id)) AS qoh, 
                         noNeg(itemuomtouom(itemsite_item_id, womatl_uom_id, NULL, womatl_qtyreq - womatl_qtyiss)) AS wobalance, 
                         qtyAllocated(itemsite_id, womatl_duedate) AS allocated, 
                         qtyOrdered(itemsite_id, womatl_duedate) AS ordered,                        
@@ -202,7 +202,7 @@ BEGIN
                 item_descrip1, 
                 item_descrip2, 
                 uom_name,
-                noNeg(itemsite_qtyonhand) AS qoh, 
+                noNeg(qtyAvailable(itemsite_id)) AS qoh, 
                 noNeg(wo_qtyord - wo_qtyrcv) AS wobalance, 
                 qtyAllocated(itemsite_id, wo_duedate) AS allocated, 
                 qtyOrdered(itemsite_id, wo_duedate) AS ordered,                        
index b2691c0..3ede5e4 100644 (file)
@@ -41,7 +41,7 @@ BEGIN
                 item_descrip1, 
                 item_descrip2, 
                 uom_name,
-                noNeg(itemsite_qtyonhand) AS qoh, 
+                noNeg(qtyAvailable(itemsite_id)) AS qoh, 
                 noNeg(itemuomtouom(itemsite_item_id, womatl_uom_id, NULL, womatl_qtyreq - womatl_qtyiss)) AS wobalance, 
                 qtyAllocated(itemsite_id, womatl_duedate) AS allocated, 
                 qtyOrdered(itemsite_id, womatl_duedate) AS ordered,
diff --git a/foundation-database/public/patches/fixflcol.sql b/foundation-database/public/patches/fixflcol.sql
new file mode 100644 (file)
index 0000000..aa526c6
--- /dev/null
@@ -0,0 +1,183 @@
+-- 4.4.1 and 4.5.0 fix - synchronize flcol_report_id
+do $$
+begin
+if fetchMetricText('ServerVersion') < '4.6.0' then
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReport'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id=285
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonth'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (375, 335)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthBudget'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (376, 336)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthDbCr'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id=387
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthPriorMonth'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (377, 337)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthPriorQuarter'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (386, 346)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthPriorYear'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (378, 338)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthQuarter'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (379, 339)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportMonthYear'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (374, 334)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportQuarter'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (380, 340)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportQuarterBudget'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (381, 341)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportQuarterPriorQuarter'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (382, 342)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportYear'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (383, 343)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportYearBudget'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (384, 344)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialReportYearPriorYear'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id in (385, 345)
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+update flcol set flcol_report_id = (select report_id from report
+                                    where report_name = 'FinancialTrend'
+                                    order by report_grade desc
+                                    limit 1)
+where flcol_report_id=388
+and flcol_id in (
+  select flcol_id
+  from flcol left join report on flcol_report_id = report_id
+  where report_id is null)
+;
+
+end if;
+end$$;
\ No newline at end of file
diff --git a/foundation-database/public/tables/bankrecimport.sql b/foundation-database/public/tables/bankrecimport.sql
new file mode 100644 (file)
index 0000000..de1fc7c
--- /dev/null
@@ -0,0 +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');
diff --git a/foundation-database/public/tables/bankrecimport.xml b/foundation-database/public/tables/bankrecimport.xml
new file mode 100644 (file)
index 0000000..f351c7c
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE openCSVAtlasDef>
+<CSVAtlas>
+ <CSVMap>
+  <Name>bankrec</Name>
+  <Table>public.bankrecimport</Table>
+  <Action>Insert</Action>
+  <PreSQL>DELETE FROM bankrecimport;</PreSQL>
+  <PostSQL>SELECT importBankrecCleared(-1);</PostSQL>
+  <CSVMapField>
+   <Name>bankrecimport_reference</Name>
+   <Type>QString</Type>
+   <Column>8</Column>
+  </CSVMapField>
+  <CSVMapField>
+   <Name>bankrecimport_descrip</Name>
+   <Type>QString</Type>
+   <Column>4</Column>
+  </CSVMapField>
+  <CSVMapField>
+   <Name>bankrecimport_comment</Name>
+   <Type>QString</Type>
+   <Column>9</Column>
+  </CSVMapField>
+  <CSVMapField>
+   <Name>bankrecimport_debit_amount</Name>
+   <Type>double</Type>
+   <Column>5</Column>
+  </CSVMapField>
+  <CSVMapField>
+   <Name>bankrecimport_credit_amount</Name>
+   <Type>double</Type>
+   <Column>6</Column>
+  </CSVMapField>
+  <CSVMapField>
+   <Name>bankrecimport_effdate</Name>
+   <Type>QDate</Type>
+   <Column>1</Column>
+  </CSVMapField>
+ </CSVMap>
+</CSVAtlas>
diff --git a/foundation-database/public/tables/checkhead.sql b/foundation-database/public/tables/checkhead.sql
new file mode 100644 (file)
index 0000000..20793d4
--- /dev/null
@@ -0,0 +1 @@
+select xt.add_column('checkhead','checkhead_alt_curr_rate', 'NUMERIC', NULL, 'public');
\ No newline at end of file
diff --git a/foundation-database/public/tables/itemsite.sql b/foundation-database/public/tables/itemsite.sql
new file mode 100644 (file)
index 0000000..5c5f7c4
--- /dev/null
@@ -0,0 +1,8 @@
+-- incident 23507:change how qoh, qoh available, and qoh netable are determined
+do $$
+begin
+if fetchMetricText('ServerVersion') < '4.7.0' then
+  update itemsite set itemsite_qtyonhand=(itemsite_qtyonhand + itemsite_nnqoh);
+  alter table itemsite drop column itemsite_nnqoh cascade;
+end if;
+end$$;
\ No newline at end of file
index 5fc9557..a5cf13d 100644 (file)
@@ -8,3 +8,11 @@ select xt.add_column('location','location_formatname', 'TEXT', NULL, 'public');
 select xt.add_index('location', 'location_formatname','location_location_formatname_idx', 'btree', 'public');
 UPDATE location SET location_formatname=formatLocationName(location_id) WHERE location_formatname IS NULL;
 
+-- incident 23507:change how qoh, qoh available, and qoh netable are determined
+select xt.add_column('location','location_usable', 'BOOLEAN', NULL, 'public');
+do $$
+begin
+if fetchMetricText('ServerVersion') < '4.7.0' then
+  update location set location_usable=true;
+end if;
+end$$;
index 01e632f..69461dd 100644 (file)
@@ -1,8 +1,8 @@
 -- Group: apOpenItems
 -- Name:  selectedpayments
--- Notes:
--- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
--- See www.xtuple.com/CPAL for the full text of the software license.
+-- Notes: 
+--        Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
+--        See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT *,
        CASE WHEN (apopen_doctype='V') THEN <? value("voucher") ?>
@@ -48,9 +48,9 @@ UNION
 SELECT apopen_id, apselect_id,
        (bankaccnt_name || '-' || bankaccnt_descrip) AS f_bank,
        (vend_number || '-' || vend_name) AS f_vendor,
-       apopen_docnumber, apopen_ponumber, apselect_amount,
+       apopen_docnumber, apopen_ponumber, -apselect_amount,
        apopen_invcnumber, apopen_doctype,
-       currToBase(apselect_curr_id, apselect_amount, CURRENT_DATE) AS apselect_amount_base,
+       currToBase(apselect_curr_id, apselect_amount, CURRENT_DATE) * -1.0 AS apselect_amount_base,
        currToBase(apselect_curr_id, apselect_amount, CURRENT_DATE) * -1.0 AS apselect_running_base,
        currConcat(apselect_curr_id) AS currAbbr
 FROM apopen, apselect, vendinfo, bankaccnt
index de92dbb..fa18e8e 100644 (file)
@@ -1,8 +1,8 @@
 -- Group: apOpenItems
 -- Name:  selectpayments
--- Notes:
--- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
--- See www.xtuple.com/CPAL for the full text of the software license.
+-- Notes: 
+--        Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
+--        See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT *,
        CASE WHEN (apopen_doctype='V') THEN <? value("voucher") ?>
@@ -73,11 +73,11 @@ SELECT apopen_id, COALESCE(apselect_id, -1) AS apselectid,
        (vend_number || '-' || vend_name) AS vendor,
        apopen_doctype, apopen_docnumber, apopen_ponumber, apopen_invcnumber,
        apopen_duedate, apopen_terms_id, apopen_docdate, apopen_status,
-       (apopen_amount - apopen_paid - apCheckPending(apopen_id)) AS amount,
-       ((apopen_amount - apopen_paid - apCheckPending(apopen_id)) / apopen_curr_rate) AS base_amount,
+       (apopen_amount - apopen_paid - apCheckPending(apopen_id))  * -1.0 AS amount,
+       ((apopen_amount - apopen_paid - apCheckPending(apopen_id)) / apopen_curr_rate) * -1.0 AS base_amount,
        ((apopen_amount - apopen_paid - apCheckPending(apopen_id)) / apopen_curr_rate) * -1.0 AS running_amount,
-       COALESCE(apselect_amount, 0.0) AS selected,
-       (COALESCE(apselect_amount, 0.0) / apopen_curr_rate) AS base_selected,
+       COALESCE(apselect_amount, 0.0) * -1.0 AS selected,
+       (COALESCE(apselect_amount, 0.0) / apopen_curr_rate) * -1.0 AS base_selected,
        (COALESCE(apselect_amount, 0.0) / apopen_curr_rate) * -1.0 AS running_selected,
        COALESCE(apselect_discount,0.0) AS discount,
        (COALESCE(apselect_discount,0.0) / apopen_curr_rate)AS base_discount,
index d251cd2..c643759 100644 (file)
@@ -16,6 +16,7 @@ SELECT (COALESCE(SUM(amount),0.0) + <? value("begBal") ?>) AS cleared_amount,
             AND (bankrecitem_source_id=gltrans_id)
             AND (bankrecitem_bankrec_id=<? value("bankrecid") ?>)
             AND (bankrecitem_cleared)
+            AND (NOT gltrans_deleted)
             AND (NOT gltrans_rec)
             AND (bankaccnt_id=<? value("bankaccntid") ?>) ) 
           UNION ALL
index e6db42d..7fd754b 100644 (file)
@@ -36,7 +36,8 @@ SELECT gltrans_id, gltrans_date, formatDate(gltrans_date) AS f_date,
     JOIN bankaccnt ON (bankaccnt_id=bankrec_bankaccnt_id)
  WHERE ((bankrecitem_bankrec_id=<? value("bankrec_id") ?>)
    AND (bankrecitem_source='GL')
-   AND (bankrecitem_source_id=gltrans_id) ) 
+   AND (bankrecitem_source_id=gltrans_id)
+   AND (NOT gltrans_deleted) ) 
 
 UNION
 
index 6214403..28a6f08 100644 (file)
@@ -29,6 +29,21 @@ SELECT   coitem_id AS id, coitem_cohead_id AS altId,
                      (coitem_price / coitem_price_invuomratio), 2) AS extpricebalance,
          round((noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) * coitem_qty_invuomratio) *
                      (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
+         END AS marginpercent,
          curr_abbr AS currAbbr,
 -- TODO - not needed, remove? (very slow)
 --         CASE WHEN (qtyAvailable(itemsite_id, coitem_scheddate) < 0.0) THEN 'error'
@@ -43,7 +58,11 @@ SELECT   coitem_id AS id, coitem_cohead_id AS altId,
        'qty' AS qtyavailable_xtnumericrole,
        'salesprice' AS coitem_price_xtnumericrole,
        'salesprice' AS baseunitprice_xtnumericrole,
+       'cost' AS coitem_unitcost_xtnumericrole,
        'curr' AS extprice_xtnumericrole,
+       'curr' AS extcost_xtnumericrole,
+       'curr' AS margin_xtnumericrole,
+       'percent' AS marginpercent_xtnumericrole,
        'curr' AS baseextprice_xtnumericrole,
        'curr' AS extpricebalance_xtnumericrole,
        'curr' AS baseextpricebalance_xtnumericrole,
index 619f501..c4ad2f9 100644 (file)
@@ -5,11 +5,20 @@
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT cohist_salesrep_id, salesrep_number, salesrep_name, cust_number, cust_name,
-       cohist_ordernumber, cohist_invcnumber, cohist_invcdate, currAbbr,
+       cohist_ordernumber, cohist_orderdate, cohist_invcnumber, cohist_invcdate, currAbbr,
        SUM(extprice) AS sumextprice,
        SUM(cohist_commission) AS sumcommission,
        SUM(baseextprice) AS sumbaseextprice,
        SUM(basecommission) AS sumbasecommission,
+<? if exists("isReport") ?>
+       formatDate(cohist_orderdate) AS f_orderdate,
+       formatDate(cohist_invcdate) AS f_invcdate,
+       formatMoney(SUM(extprice)) AS f_sumextprice,
+       formatMoney(SUM(baseextprice)) AS f_sumbaseextprice,
+       formatMoney(SUM(cohist_commission)) AS f_sumcommission,
+       formatMoney(SUM(basecommission)) AS f_sumbasecommission,
+<? endif ?>
+       <? value("return") ?> AS cohist_invcdate_xtnullrole,
        'curr' AS sumextprice_xtnumericrole,
        'curr' AS sumcommission_xtnumericrole,
        'curr' AS sumbaseextprice_xtnumericrole,
@@ -23,14 +32,10 @@ FROM saleshistory
 <? endif ?>
 WHERE ((cohist_commission <> 0)
     AND(cohist_invcdate BETWEEN <? value("startDate") ?> AND <? value("endDate") ?>)
-    <? if exists("includeMisc") ?>
-    AND (COALESCE(cohist_misc_type, '') <> 'T')
-    AND (COALESCE(cohist_misc_type, '') <> 'F')
-    <? endif ?>
     <? if exists("salesrep_id") ?>
     AND (cohist_salesrep_id=<? value("salesrep_id") ?>)
     <? endif ?>
       )
 GROUP BY cohist_salesrep_id, salesrep_number, salesrep_name, cust_number, cust_name,
-         cohist_ordernumber, cohist_invcnumber, cohist_invcdate, currAbbr
+         cohist_ordernumber, cohist_orderdate, cohist_invcnumber, cohist_invcdate, currAbbr
 ORDER BY salesrep_number, cust_number, cohist_invcdate;
index 8dc7a25..18982ae 100644 (file)
@@ -4,21 +4,57 @@
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
-SELECT
-       COALESCE(cohead_id,-1) AS cohead_id, cust_id, cohist_ponumber,
-       cust_custtype_id, custtype_code,
-       cohist_cust_id, SUM(extcost) AS extcost,
+SELECT cohead_id, cust_id, cohist_ponumber,
+       custtype_id, custtype_code,
+       cohist_cust_id, cohist_ordernumber,
+       cust_number, cust_name, currAbbr,
+       cohist_orderdate, cohist_invcdate,
+       CASE WHEN (COALESCE(cohist_invcnumber, '-1') IN ('', '-1')) THEN  <? value("credit") ?>
+            ELSE cohist_invcnumber
+       END AS invoicenumber,
+       SUM(extprice) AS extprice,
+       SUM(baseextprice) AS baseextprice,
+       SUM(extcost) AS extcost,
+       SUM(margin) AS margin,
+       CASE WHEN (SUM(baseextprice) > 0.0) THEN
+            ROUND(SUM(margin) / SUM(baseextprice), 4)
+            ELSE 0.0
+       END AS marginpercent,
+<? if exists("isReport") ?>
+       formatDate(cohist_orderdate) AS f_orderdate,
+       formatDate(cohist_invcdate) AS f_invcdate,
+       formatMoney(SUM(extprice)) AS f_extprice,
+       formatMoney(SUM(baseextprice)) AS f_baseextprice,
+       formatMoney(SUM(extcost)) AS f_extcost,
+       formatMoney(SUM(margin)) AS f_margin,
+<? endif ?>
+       <? value("return") ?> AS cohist_invcdate_xtnullrole,
+       'curr' AS extprice_xtnumericrole,
+       'curr' AS baseextprice_xtnumericrole,
        'curr' AS extcost_xtnumericrole,
+       'curr' AS margin_xtnumericrole,
+       'percent' AS marginpercent_xtnumericrole,
+       0 AS baseextprice_xttotalrole,
        0 AS extcost_xttotalrole,
-       cohist_ordernumber,
-       cust_number, cust_name, invoicenumber,
-       cohist_orderdate, cohist_invcdate,
-       SUM(baseextprice) AS extended,
-       'curr' AS extended_xtnumericrole,
-       0 AS extended_xttotalrole
-FROM saleshistory
-  LEFT OUTER JOIN cohead ON (cohead_number=cohist_ordernumber)
-WHERE ((cohist_invcdate BETWEEN <? value("startDate") ?> AND  <? value("endDate") ?>)
+       0 AS margin_xttotalrole
+<? if exists("includeMisc") ?>
+  FROM saleshistorymisc
+<? else ?>
+  FROM saleshistory
+<? endif ?>
+WHERE ( (true)
+<? if exists("startDate") ?>
+  AND  (cohist_invcdate >= <? value("startDate") ?>)
+<? endif ?>
+<? if exists("endDate") ?>
+  AND  (cohist_invcdate <= <? value("endDate") ?>)
+<? endif ?>
+<? if exists("shipStartDate") ?>
+  AND  (cohist_shipdate >= <? value("shipStartDate") ?>)
+<? endif ?>
+<? if exists("shipEndDate") ?>
+  AND  (cohist_shipdate <= <? value("shipEndDate") ?>)
+<? endif ?>
 <? if exists("cust_id") ?>
    AND (cohist_cust_id=<? value("cust_id") ?>)
 <? endif ?>
@@ -26,7 +62,7 @@ WHERE ((cohist_invcdate BETWEEN <? value("startDate") ?> AND  <? value("endDate"
    AND (cohist_shipto_id=<? value("shipto_id") ?>)
 <? endif ?>
 <? if exists("custtype_id") ?>
-   AND (cust_custtype_id=<? value("custtype_id") ?>)
+   AND (custtype_id=<? value("custtype_id") ?>)
 <? endif ?>
 <? if exists("custtype_pattern") ?>
    AND (custtype_code ~ <? value("custtype_pattern") ?>)
@@ -43,24 +79,31 @@ WHERE ((cohist_invcdate BETWEEN <? value("startDate") ?> AND  <? value("endDate"
                      AND   (custgrp_name ~ <? value("custgrp_pattern") ?>) )) )
 <? endif ?>
 <? if exists("warehous_id") ?>
-   AND (itemsite_warehous_id=<? value("warehous_id") ?>)
+   AND (warehous_id=<? value("warehous_id") ?>)
 <? endif ?>
 <? if exists("item_id") ?>
-  AND  (itemsite_item_id=<? value("item_id") ?>)
+  AND  (item_id=<? value("item_id") ?>)
 <? endif ?>
 <? if exists("prodcat_id") ?>
-   AND (item_prodcat_id=<? value("prodcat_id") ?>)
+   AND (prodcat_id=<? value("prodcat_id") ?>)
 <? endif ?>
 <? if exists("prodcat_pattern") ?>
-   AND (item_prodcat_id IN (SELECT prodcat_id
-                            FROM prodcat
-                            WHERE (prodcat_code ~ <? value("prodcat_pattern") ?>)))
+   AND (prodcat_id IN (SELECT prodcat_id
+                       FROM prodcat
+                       WHERE (prodcat_code ~ <? value("prodcat_pattern") ?>)))
 <? endif ?>
 <? if exists("salesrep_id") ?>
    AND (cohist_salesrep_id=<? value("salesrep_id") ?>)
+<? endif ?>
+<? if exists("shipzone_id") ?>
+  AND (cohist_shipzone_id=<? value("shipzone_id") ?>)
+<? endif ?>
+<? if exists("saletype_id") ?>
+  AND (cohist_saletype_id=<? value("saletype_id") ?>)
 <? endif ?>
       )
-GROUP BY cohead_id, cust_id,cust_number,cust_custtype_id,cohist_cust_id,custtype_code,
-         cust_name,cohist_ordernumber, cohist_ponumber,
-         invoicenumber,cohist_orderdate, cohist_invcdate
+GROUP BY cohead_id, cust_id, cust_number, custtype_id,
+         cohist_cust_id, custtype_code, currAbbr,
+         cust_name, cohist_ordernumber, cohist_ponumber,
+         cohist_invcnumber, cohist_orderdate, cohist_invcdate
 ORDER BY cohist_invcdate, cohist_orderdate;
index a930353..df6f597 100644 (file)
@@ -29,44 +29,29 @@ FROM (
              invcnt_tagdate AS tagdate,
              item_number, (item_descrip1 || item_descrip2) AS item_descrip, warehous_code,
             CASE WHEN (location_id IS NOT NULL) THEN
-               location_name
+               formatLocationName(location_id)
                ELSE <? value("all") ?> END AS loc_specific,
-             CASE WHEN (invcnt_location_id IS NOT NULL)
-               THEN (SELECT SUM(itemloc_qty)
-                     FROM itemloc JOIN location ON (location_id=itemloc_location_id)
-                     WHERE ((itemloc_itemsite_id=itemsite_id)
-                       AND  (itemloc_location_id=invcnt_location_id)
-                       AND  (location_netable)))
-               ELSE itemsite_qtyonhand
-             END AS qoh,
-             CASE WHEN (invcnt_location_id IS NOT NULL)
-               THEN (SELECT SUM(itemloc_qty)
-                     FROM itemloc JOIN location ON (location_id=itemloc_location_id)
-                     WHERE ((itemloc_itemsite_id=itemsite_id)
-                       AND  (itemloc_location_id=invcnt_location_id)
-                       AND  (NOT location_netable)))
-               ELSE itemsite_nnqoh
-             END AS nnqoh,
+             qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) AS qoh,
       <? if exists("showSlips") ?>
              calcTotalSlipQty(invcnt_id) AS qohafter,
-             (calcTotalSlipQty(invcnt_id) - (itemsite_qtyonhand + itemsite_nnqoh)) AS variance,
+             (calcTotalSlipQty(invcnt_id) - qtyAtLocation(invcnt_itemsite_id, invcnt_location_id)) AS variance,
              CASE WHEN (calcTotalSlipQty(invcnt_id) IS NULL) THEN NULL
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (calcTotalSlipQty(invcnt_id) > 0)) THEN 1
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (calcTotalSlipQty(invcnt_id) < 0)) THEN -1
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (calcTotalSlipQty(invcnt_id) = 0)) THEN 0
-               ELSE ((1 - (calcTotalSlipQty(invcnt_id) / (itemsite_qtyonhand + itemsite_nnqoh))) * -1)
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (calcTotalSlipQty(invcnt_id) > 0)) THEN 1
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (calcTotalSlipQty(invcnt_id) < 0)) THEN -1
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (calcTotalSlipQty(invcnt_id) = 0)) THEN 0
+               ELSE ((1 - (calcTotalSlipQty(invcnt_id) / qtyAtLocation(invcnt_itemsite_id, invcnt_location_id))) * -1)
              END AS varianceprcnt,
-             (itemCost(itemsite_id) * (calcTotalSlipQty(invcnt_id) - (itemsite_qtyonhand + itemsite_nnqoh))) AS variancecost,
+             (itemCost(itemsite_id) * (calcTotalSlipQty(invcnt_id) - qtyAtLocation(invcnt_itemsite_id, invcnt_location_id))) AS variancecost,
       <? else ?>
              COALESCE(invcnt_qoh_after, 0.0) AS qohafter,
-             (invcnt_qoh_after - (itemsite_qtyonhand + itemsite_nnqoh)) AS variance,
+             (invcnt_qoh_after - qtyAtLocation(invcnt_itemsite_id, invcnt_location_id)) AS variance,
              CASE WHEN (invcnt_qoh_after IS NULL) THEN NULL
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (invcnt_qoh_after > 0)) THEN 1
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (invcnt_qoh_after < 0)) THEN -1
-                  WHEN (((itemsite_qtyonhand + itemsite_nnqoh) = 0) AND (invcnt_qoh_after = 0)) THEN 0
-               ELSE ((1 - (invcnt_qoh_after / (itemsite_qtyonhand + itemsite_nnqoh))) * -1)
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (invcnt_qoh_after > 0)) THEN 1
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (invcnt_qoh_after < 0)) THEN -1
+                  WHEN ((qtyAtLocation(invcnt_itemsite_id, invcnt_location_id) = 0) AND (invcnt_qoh_after = 0)) THEN 0
+               ELSE ((1 - (invcnt_qoh_after / qtyAtLocation(invcnt_itemsite_id, invcnt_location_id))) * -1)
              END AS varianceprcnt,
-             (itemCost(itemsite_id) * (invcnt_qoh_after - (itemsite_qtyonhand + itemsite_nnqoh))) AS variancecost,
+             (itemCost(itemsite_id) * (invcnt_qoh_after - qtyAtLocation(invcnt_itemsite_id, invcnt_location_id))) AS variancecost,
       <? endif ?>
              item_number AS orderby,
              0 AS xtindentrole
@@ -101,7 +86,6 @@ FROM (
              '' AS warehous_code,
              '' AS loc_specific,
              NULL AS qoh,
-             NULL AS nnqoh,
              cntslip_qty AS qohafter,
              NULL AS variance, NULL AS varianceprcnt, 0 AS variancecost,
              item_number AS orderby,
index 7a95ea0..baa6a66 100644 (file)
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT id, type, locationname, defaultlocation,
-                       location_netable, lotserial, f_expiration, expired,
-                        qty, qtytagged, (qty + qtytagged) AS balance,
-                        'qty' AS qty_xtnumericrole,
-                        'qty' AS qtytagged_xtnumericrole,
-                        'qty' AS balance_xtnumericrole,
-                        CASE WHEN expired THEN 'error' END AS qtforegroundrole, 
-                        CASE WHEN expired THEN 'error' 
-                             WHEN defaultlocation AND expired = false THEN 'altemphasis' 
-                        ELSE null END AS defaultlocation_qtforegroundrole, 
-                        CASE WHEN expired THEN 'error' 
-                             WHEN qty > 0 AND expired = false THEN 'altemphasis' 
-                        ELSE null END AS qty_qtforegroundrole 
-                 FROM ( 
-                <? if exists("cNoIncludeLotSerial") ?>
-                SELECT location_id AS id, <? value("locationType") ?> AS type,
-                       formatLocationName(location_id) AS locationname,
-                       CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
-                            WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
-                            WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
-                             ELSE FALSE
-                        END AS defaultlocation,
-                       location_netable,
-                       TEXT('') AS lotserial,
-                       TEXT(<? value("na") ?>) AS f_expiration, FALSE AS expired,
-                       qtyLocation(location_id, NULL, NULL, NULL, itemsite_id, itemlocdist_order_type, itemlocdist_order_id, itemlocdist_id) AS qty,
-                       itemlocdistQty(location_id, itemlocdist_id) AS qtytagged 
-                FROM itemlocdist, location, itemsite 
-                WHERE ( (itemlocdist_itemsite_id=itemsite_id)
-                 AND (itemsite_loccntrl)
-                 AND (itemsite_warehous_id=location_warehous_id)
-                 AND (validLocation(location_id, itemsite_id))
-                 AND (itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
-                <? elseif exists("cIncludeLotSerial") ?>
-                SELECT itemloc_id AS id, <? value("itemlocType") ?> AS type,
-                       COALESCE(formatLocationName(location_id),
-                                <? value("undefined") ?>) AS locationname,
-                       (location_id IS NOT NULL AND
-                        CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
-                             WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
-                             WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
-                              ELSE FALSE
-                         END) AS defaultlocation,
-                       COALESCE(location_netable, false) AS location_netable,
-                       ls_number AS lotserial,
-                       CASE WHEN (itemsite_perishable) THEN formatDate(itemloc_expiration)
-                            ELSE <? value("na") ?>
-                       END AS f_expiration,
-                       CASE WHEN (itemsite_perishable) THEN (itemloc_expiration < CURRENT_DATE)
-                            ELSE FALSE 
-                       END AS expired,
-                       qtyLocation(itemloc_location_id, itemloc_ls_id, itemloc_expiration, itemloc_warrpurc, itemsite_id, itemlocdist_order_type, itemlocdist_order_id, itemlocdist_id) AS qty,
-                       ( SELECT COALESCE(SUM(target.itemlocdist_qty), 0)
-                         FROM itemlocdist AS target
-                         WHERE ( (target.itemlocdist_source_type='I')
-                          AND (target.itemlocdist_source_id=itemloc_id)
-                          AND (target.itemlocdist_itemlocdist_id=source.itemlocdist_id)) ) AS qtytagged 
-                FROM itemlocdist AS source, itemsite, itemloc 
-                   LEFT OUTER JOIN location ON (itemloc_location_id=location_id) 
-                   LEFT OUTER JOIN ls ON (itemloc_ls_id=ls_id) 
-                WHERE ( (source.itemlocdist_itemsite_id=itemsite_id)
-                 AND (itemloc_itemsite_id=itemsite_id)
-                 AND (source.itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
-                 UNION 
-                SELECT location_id AS id, <? value("locationType") ?> AS type,
-                       formatLocationName(location_id) AS locationname,
-                       CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
-                            WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
-                            WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
-                             ELSE FALSE
-                        END AS defaultlocation,
-                       location_netable,
-                       TEXT('') AS lotserial,
-                       TEXT(<? value("na") ?>) AS f_expiration, FALSE AS expired,
-                       qtyLocation(location_id, NULL, NULL, NULL, itemsite_id, itemlocdist_order_type, itemlocdist_order_id, itemlocdist_id) AS qty,
-                       itemlocdistQty(location_id, itemlocdist_id) AS qtytagged 
-                FROM itemlocdist, location, itemsite 
-                WHERE ( (itemlocdist_itemsite_id=itemsite_id)
-                 AND (itemsite_loccntrl)
-                 AND (itemsite_warehous_id=location_warehous_id)
-                 AND (validLocation(location_id, itemsite_id))
-                  AND (itemsite_id=<? value("itemsite_id") ?> ) 
-                 AND (location_id NOT IN (SELECT DISTINCT itemloc_location_id FROM itemloc WHERE (itemloc_itemsite_id=itemsite_id)))
-                 AND (itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
-                <? endif ?>
-                ) AS data 
-                 WHERE ((TRUE) 
-                <? if exists("showOnlyTagged") ?>
-                AND (qtytagged != 0) 
-                <? endif ?>
-                 <? if exists("showQtyOnly") ?>
-                 AND (qty > 0) 
-                 <? endif ?>
-                ) ORDER BY locationname;
+           location_netable, location_usable, lotserial, f_expiration, expired,
+           qty, qtytagged, (qty + qtytagged) AS balance,
+           'qty' AS qty_xtnumericrole,
+           'qty' AS qtytagged_xtnumericrole,
+           'qty' AS balance_xtnumericrole,
+           CASE WHEN expired THEN 'error' END AS qtforegroundrole, 
+           CASE WHEN defaultlocation AND expired = false THEN 'altemphasis' 
+                WHEN expired THEN 'error' 
+                ELSE null END AS defaultlocation_qtforegroundrole, 
+           CASE WHEN expired THEN 'error' 
+                WHEN qty > 0 AND expired = false THEN 'altemphasis' 
+                ELSE null END AS qty_qtforegroundrole 
+FROM ( 
+  <? if exists("cNoIncludeLotSerial") ?>
+    SELECT location_id AS id, <? value("locationType") ?> AS type,
+           formatLocationName(location_id) AS locationname,
+           CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
+                WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
+                WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
+                ELSE FALSE
+           END AS defaultlocation,
+           COALESCE(location_netable, true) AS location_netable,
+           COALESCE(location_usable, true) AS location_usable,
+           TEXT('') AS lotserial,
+           TEXT(<? value("na") ?>) AS f_expiration, FALSE AS expired,
+           qtyLocation(location_id, NULL, NULL, NULL,
+                       itemsite_id, itemlocdist_order_type, itemlocdist_order_id, itemlocdist_id) AS qty,
+           itemlocdistQty(location_id, itemlocdist_id) AS qtytagged 
+    FROM itemlocdist, location, itemsite 
+    WHERE ( (itemlocdist_itemsite_id=itemsite_id)
+      AND (itemsite_loccntrl)
+      AND (itemsite_warehous_id=location_warehous_id)
+      AND (validLocation(location_id, itemsite_id))
+      AND (itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
+  <? elseif exists("cIncludeLotSerial") ?>
+    SELECT itemloc_id AS id, <? value("itemlocType") ?> AS type,
+           COALESCE(formatLocationName(location_id),
+           <? value("undefined") ?>) AS locationname,
+           (location_id IS NOT NULL AND
+             CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
+                  WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
+                  WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
+                  ELSE FALSE
+             END) AS defaultlocation,
+           COALESCE(location_netable, true) AS location_netable,
+           COALESCE(location_usable, true) AS location_usable,
+           ls_number AS lotserial,
+           CASE WHEN (itemsite_perishable) THEN formatDate(itemloc_expiration)
+                ELSE <? value("na") ?>
+           END AS f_expiration,
+           CASE WHEN (itemsite_perishable) THEN (itemloc_expiration < CURRENT_DATE)
+                ELSE FALSE 
+           END AS expired,
+           qtyLocation(itemloc_location_id, itemloc_ls_id, itemloc_expiration,
+                       itemloc_warrpurc, itemsite_id, itemlocdist_order_type,
+                       itemlocdist_order_id, itemlocdist_id) AS qty,
+           ( SELECT COALESCE(SUM(target.itemlocdist_qty), 0)
+             FROM itemlocdist AS target
+             WHERE ( (target.itemlocdist_source_type='I')
+               AND (target.itemlocdist_source_id=itemloc_id)
+               AND (target.itemlocdist_itemlocdist_id=source.itemlocdist_id)) ) AS qtytagged 
+    FROM itemlocdist AS source, itemsite, itemloc 
+         LEFT OUTER JOIN location ON (itemloc_location_id=location_id) 
+         LEFT OUTER JOIN ls ON (itemloc_ls_id=ls_id) 
+   WHERE ( (source.itemlocdist_itemsite_id=itemsite_id)
+     AND (itemloc_itemsite_id=itemsite_id)
+     AND (source.itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
+    UNION 
+    SELECT location_id AS id, <? value("locationType") ?> AS type,
+           formatLocationName(location_id) AS locationname,
+           CASE WHEN (<? value("transtype") ?> = 'R' AND location_id=itemsite_recvlocation_id) THEN TRUE
+                WHEN (<? value("transtype") ?> = 'I' AND location_id=itemsite_issuelocation_id) THEN TRUE
+                WHEN (<? value("transtype") ?> = 'O' AND location_id=itemsite_location_id) THEN TRUE
+                ELSE FALSE
+           END AS defaultlocation,
+           COALESCE(location_netable, true) AS location_netable,
+           COALESCE(location_usable, true) AS location_usable,
+           TEXT('') AS lotserial,
+           TEXT(<? value("na") ?>) AS f_expiration, FALSE AS expired,
+           qtyLocation(location_id, NULL, NULL, NULL,
+                       itemsite_id, itemlocdist_order_type, itemlocdist_order_id, itemlocdist_id) AS qty,
+           itemlocdistQty(location_id, itemlocdist_id) AS qtytagged 
+    FROM itemlocdist, location, itemsite 
+    WHERE ( (itemlocdist_itemsite_id=itemsite_id)
+      AND (itemsite_loccntrl)
+      AND (itemsite_warehous_id=location_warehous_id)
+      AND (validLocation(location_id, itemsite_id))
+      AND (itemsite_id=<? value("itemsite_id") ?> ) 
+      AND (location_id NOT IN (SELECT DISTINCT itemloc_location_id
+                               FROM itemloc
+                               WHERE (itemloc_itemsite_id=itemsite_id)))
+      AND (itemlocdist_id=<? value("itemlocdist_id") ?>) ) 
+  <? endif ?>
+  ) AS data 
+WHERE ((TRUE) 
+   AND ( (<? value("transtype") ?> != 'I') OR (<? value("transtype") ?> = 'I' AND location_usable) )
+<? if exists("showOnlyTagged") ?>
+  AND (qtytagged != 0) 
+<? endif ?>
+<? if exists("showQtyOnly") ?>
+  AND (qty > 0) 
+<? endif ?>
+) ORDER BY locationname;
index 2eee3c9..6996987 100644 (file)
@@ -94,10 +94,10 @@ FROM (
       GROUP BY cohead_id, item_number, cust_number,
                cust_name, cohead_orderdate, pack_id, coitem_scheddate
   <? if exists("onlyShowShortages") ?>
-      HAVING (MIN(noNeg(itemsite_qtyonhand) +
+      HAVING (MIN(noNeg(qtyAvailable(itemsite_id)) +
                   qtyOrdered(itemsite_id, coitem_scheddate) -
                   qtyAllocated(itemsite_id, coitem_scheddate)) < 0
-              OR MIN(noNeg(itemsite_qtyonhand) +
+              OR MIN(noNeg(qtyAvailable(itemsite_id)) +
                   qtyOrdered(itemsite_id, coitem_scheddate) -
                   noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned)) < 0
            )
@@ -108,7 +108,7 @@ FROM (
             item_number,
             item_number AS trueitem_number,
             (item_descrip1 || ' ' || item_descrip2) AS descrip,
-            uom_name, noNeg(itemsite_qtyonhand) AS qoh,
+            uom_name, noNeg(qtyAvailable(itemsite_id)) AS qoh,
             noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) AS sobalance,
             qtyAllocated(itemsite_id, coitem_scheddate) AS allocated,
             qtyOrdered(itemsite_id, coitem_scheddate) AS ordered,
@@ -138,8 +138,8 @@ FROM (
                                   WHERE(custtype_code ~ <? value("custtype_pattern") ?>)))
 <? endif ?>
 <? if exists("onlyShowShortages") ?>
-        AND ((noNeg(itemsite_qtyonhand) + qtyOrdered(itemsite_id, coitem_scheddate) - qtyAllocated(itemsite_id, coitem_scheddate) < 0)
-          OR (noNeg(itemsite_qtyonhand) + qtyOrdered(itemsite_id, coitem_scheddate) - noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) < 0))
+        AND ((noNeg(qtyAvailable(itemsite_id)) + qtyOrdered(itemsite_id, coitem_scheddate) - qtyAllocated(itemsite_id, coitem_scheddate) < 0)
+          OR (noNeg(qtyAvailable(itemsite_id)) + qtyOrdered(itemsite_id, coitem_scheddate) - noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) < 0))
 <? endif ?>
     )
 <? if exists("showWoSupply") ?>
@@ -167,7 +167,7 @@ FROM (
            AND (wo_status IN ('E','R','I'))
            AND (wo_qtyord-wo_qtyrcv > 0)
            AND (noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned-qtyatshipping(coitem_id)) >
-            (SELECT itemsite_qtyonhand FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
+            (SELECT qtyAvailable(itemsite_id) FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
      WHERE ((coitem_cohead_id=cohead_id)
         AND (coitem_itemsite_id=itemsite_id)
         AND (itemsite_warehous_id=warehous_id)
@@ -184,8 +184,8 @@ FROM (
                                   WHERE(custtype_code ~ <? value("custtype_pattern") ?>)))
   <? endif ?>
   <? if exists("onlyShowShortages") ?>
-        AND ((noNeg(itemsite_qtyonhand) + qtyOrdered(itemsite_id, coitem_scheddate) - qtyAllocated(itemsite_id, coitem_scheddate) < 0)
-          OR (noNeg(itemsite_qtyonhand) + qtyOrdered(itemsite_id, coitem_scheddate) - noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) < 0))
+        AND ((noNeg(qtyAvailable(itemsite_id)) + qtyOrdered(itemsite_id, coitem_scheddate) - qtyAllocated(itemsite_id, coitem_scheddate) < 0)
+          OR (noNeg(qtyAvailable(itemsite_id)) + qtyOrdered(itemsite_id, coitem_scheddate) - noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) < 0))
   <? endif ?>
   )
 <? endif ?>
index ddeabd6..53ab1ce 100644 (file)
@@ -37,7 +37,7 @@ FROM (SELECT
              END AS altId,
              item_number, item_descrip1, item_descrip2, item_inv_uom_id,
              warehous_id, warehous_code, itemsite_leadtime,
-             itemsite_qtyonhand AS qoh,
+             qtyAvailable(itemsite_id) AS qoh,
              CASE WHEN itemsite_useparams THEN itemsite_reorderlevel
                   ELSE 0.0
              END AS reorderlevel,
index b607ba4..cfc41cd 100644 (file)
@@ -8,6 +8,7 @@
 SELECT *,
        <? value("na") ?> AS locationname_xtnullrole,
        <? value("na") ?> AS netable_xtnullrole,
+       <? value("na") ?> AS usable_xtnullrole,
        <? value("na") ?> AS lotserial_xtnullrole,
        <? value("na") ?> AS expiration_xtnullrole,
        <? value("na") ?> AS warranty_xtnullrole,
@@ -25,6 +26,8 @@ FROM (SELECT itemloc_id, 1 AS type, warehous_code,
              END AS locationname,
              CASE WHEN (location_id IS NOT NULL) THEN location_netable
              END AS netable,
+             CASE WHEN (location_id IS NOT NULL) THEN location_usable
+             END AS usable,
              CASE WHEN (itemsite_controlmethod IN ('L', 'S')) THEN
                         formatlotserialnumber(itemloc_ls_id)
              END AS lotserial,
@@ -88,6 +91,7 @@ FROM (SELECT itemloc_id, 1 AS type, warehous_code,
              itemsite_warrpurc, NULL AS itemloc_warrpurc,
              NULL AS locationname,
              NULL AS netable,
+             NULL AS usable,
              NULL AS lotserial,
              NULL AS expiration,
              NULL AS warranty,
index 67ee698..20b3648 100644 (file)
@@ -29,11 +29,16 @@ SELECT invchead_id, cust_id,
          invchead_invcnumber AS docnumber,
          findCustomerForm(cust_id, 'I') AS reportname,
        <? endif ?>
+       CASE WHEN (calcInvoiceAmt(invchead_id,'S') != 0.0)
+              THEN calcInvoiceAmt(invchead_id,'M')
+            ELSE 0.0
+       END AS margin,
        CASE WHEN (calcInvoiceAmt(invchead_id,'S') != 0.0)
               THEN (calcInvoiceAmt(invchead_id,'M') / calcInvoiceAmt(invchead_id,'S'))
             ELSE 1.0
        END AS marginpercent,
        'percent' AS marginpercent_xtnumericrole,
+       'curr' AS margin_xtnumericrole,
        'curr' AS extprice_xtnumericrole,
        'curr' AS balance_xtnumericrole,
        CASE WHEN (aropen_id IS NULL) THEN 'Unposted' END AS balance_qtdisplayrole
index 377f256..ba1ab0c 100644 (file)
@@ -15,18 +15,23 @@ SELECT ipsitem_id AS id, 1 AS altid,
        price.uom_name AS priceuom,
        ((COALESCE(ipsitem_discntprcnt, 0.0) * 100) + ipsitem_price) AS price,
        (COALESCE(ipsitem_fixedamtdiscount, 0.0) + 0.00) AS fixedAmt,
-       noNeg(CASE WHEN (ipsitem_type='N') THEN
+       noNeg(CASE WHEN (ipsitem_item_id IS NULL) THEN
+                   NULL
+                  WHEN (ipsitem_type='N') THEN
                    ipsitem_price
                   WHEN (ipsitem_type='D') THEN
                    (item_listprice - (item_listprice * COALESCE(ipsitem_discntprcnt, 0.0)) - COALESCE(ipsitem_fixedamtdiscount, 0.0))
                   WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups') AND fetchMetricBool('WholesalePriceCosting')) THEN
                    (item_listcost / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                   WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups')) THEN
-                   (itemCost(itemsite_id) / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
+                   (itemCost(itemsite_id) / itemuomtouomratio(item_id, ipsitem_qty_uom_id, ipsitem_price_uom_id) /
+                   (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                   WHEN (ipsitem_type = 'M' AND fetchMetricBool('WholesalePriceCosting')) THEN
                    (item_listcost + (item_listcost * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                   WHEN (ipsitem_type = 'M') THEN
-                   (itemCost(itemsite_id) + (itemCost(itemsite_id) * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
+                   (itemCost(itemsite_id) / itemuomtouomratio(item_id, ipsitem_qty_uom_id, ipsitem_price_uom_id) +
+                    (itemCost(itemsite_id) / itemuomtouomratio(item_id, ipsitem_qty_uom_id, ipsitem_price_uom_id) * ipsitem_discntprcnt) +
+                    ipsitem_fixedamtdiscount)
                   ELSE 0.0
              END) AS netPrice,
        CASE WHEN (ipsitem_type='N') THEN <? value("nominal") ?>
index c4389b9..454227f 100644 (file)
@@ -4,8 +4,8 @@
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
-SELECT formatQty(itemsite_qtyonhand) AS f_qoh,itemsite_qtyonhand
-       qtyAllocated(itemsite_id, findPeriodStart(<? value("cursorId") ?>),
+SELECT qtyNetable(itemsite_id) AS qoh, formatQty(qtyNetable(itemsite_id)) AS f_qoh,
+       qtyAllocated(itemsite_id, findPeriodStart(<? value("cursorId") ?>),
                        findPeriodEnd(<? value("cursorId") ?>)) AS allocations<? value("counter") ?>,
        qtyOrdered(itemsite_id, findPeriodStart(<? value("cursorId") ?>),
                        findPeriodEnd(<? value("cursorId") ?>)) AS orders<? value("counter") ?>,
index 81385aa..bb58084 100644 (file)
@@ -20,12 +20,17 @@ SELECT DISTINCT
 <? endforeach ?>
        firstline(cohead_ordercomments) AS notes,
        calcSalesOrderAmt(cohead_id) AS ordertotal,
+       CASE WHEN (calcSalesOrderAmt(cohead_id,'S') != 0.0)
+              THEN calcSalesOrderAmt(cohead_id,'M')
+            ELSE 0.0
+       END AS ordermargin,
        CASE WHEN (calcSalesOrderAmt(cohead_id,'S') != 0.0)
               THEN (calcSalesOrderAmt(cohead_id,'M') / calcSalesOrderAmt(cohead_id,'S'))
             ELSE 1.0
        END AS ordermarginpercent,
        'percent' AS ordermarginpercent_xtnumericrole,
-       'extprice' AS ordertotal_xtnumericrole
+       'extprice' AS ordertotal_xtnumericrole,
+       'extprice' AS ordermargin_xtnumericrole
 FROM cohead 
      JOIN custinfo ON (cohead_cust_id=cust_id) 
      JOIN custtype ON (cust_custtype_id=custtype_id)
index f211460..ed6d5f1 100644 (file)
@@ -130,7 +130,7 @@ SELECT prjtask_id AS id,
   LEFT OUTER JOIN addr ON (cntct_addr_id=addr_id)
 
  WHERE (prjtask_prj_id = <? value("prj_id") ?> )
- GROUP BY custinfo.cust_name, prjtask.prjtask_id, addr.addr_city, addr.addr_state, cntct_name
+ GROUP BY prjtask_prj_id, custinfo.cust_name, prjtask.prjtask_id, addr.addr_city, addr.addr_state, cntct_name, prjtask.prjtask_number, prjtask.prjtask_status, prjtask_username, prjtask.prjtask_owner_username, prjtask_name, prjtask_descrip, prjtask_due_date, prjtask_assigned_date, prjtask_start_date, prjtask_completed_date, prjtask_hours_budget, prjtask_hours_actual, prjtask_exp_budget, prjtask_exp_actual
 
 <? if exists("showIn") ?>
 UNION ALL
@@ -221,7 +221,7 @@ UNION ALL
 SELECT DISTINCT -1 AS id, 
        10 AS type,
        '0' AS subtype,
-       1 AS section,
+       2 AS section,
        <? value("quotes") ?> AS section_qtdisplayrole,
        <? value("quotes") ?> AS name,
        NULL::text AS status,
@@ -263,7 +263,7 @@ UNION ALL
 SELECT quhead_id AS id, 
        15 AS type,
        quhead_number AS subtype,
-       1 AS section,
+       2 AS section,
        <? value("quotes") ?> AS section_qtdisplayrole,
        quhead_number AS name,
        CASE WHEN (quhead_status = 'C') THEN 
@@ -316,7 +316,7 @@ UNION ALL
 SELECT quitem_id AS id, 
        17 AS type,
        quhead_number AS subtype,
-       1 AS section,
+       2 AS section,
        <? value("quotes") ?> AS section_qtdisplayrole,
        quitem_linenumber::text AS name, 
        CASE WHEN (quhead_status = 'C') THEN 
@@ -370,7 +370,7 @@ UNION ALL
 SELECT quhead_id AS id, 
        18 AS type,
        quhead_number AS subtype,
-       1 AS section,
+       2 AS section,
        <? value("quotes") ?> AS section_qtdisplayrole,
        <? value("total") ?> AS name,
        NULL AS status,
@@ -414,7 +414,7 @@ UNION ALL
 SELECT -1 AS id, 
        19 AS type,
        MAX(quhead_number) AS subtype,
-       1 AS section,
+       2 AS section,
        <? value("quotes") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("quotes") ?> AS name,
        NULL AS status,
@@ -458,7 +458,7 @@ UNION ALL
 SELECT DISTINCT -1 AS id, 
        20 AS type,
        '0' AS subtype,
-       2 AS section,
+       3 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        <? value("sos") ?> AS name,
        NULL::text AS status,
@@ -497,7 +497,7 @@ UNION ALL
 SELECT cohead_id AS id, 
        25 AS type,
        cohead_number::text AS subtype,
-       2 AS section,
+       3 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        cohead_number::text AS name,
       COALESCE((SELECT 
@@ -559,7 +559,7 @@ UNION ALL
 SELECT coitem_id AS id, 
        27 AS type,
        cohead_number::text AS subtype,
-       2 AS section,
+       3 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        coitem_linenumber::text AS name, 
        CASE WHEN (coitem_status = 'O') THEN
@@ -608,7 +608,7 @@ UNION ALL
 SELECT cohead_id AS id, 
        28 AS type,
        cohead_number::text AS subtype,
-       2 AS section,
+       3 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        <? value("total") ?> AS name,
        NULL AS status,
@@ -649,7 +649,7 @@ UNION ALL
 SELECT -1 AS id, 
        29 AS type,
        MAX(cohead_number::text) AS subtype,
-       2 AS section,
+       3 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("sos") ?> AS name,
        NULL AS status,
@@ -690,7 +690,7 @@ UNION ALL
 SELECT DISTINCT -1 AS id, 
        30 AS type,
        '0' AS subtype,
-       3 AS section,
+       4 AS section,
        <? value("invoices") ?> AS section_qtdisplayrole,
        <? value("invoices") ?> AS name,
        NULL::text AS status,
@@ -729,7 +729,7 @@ UNION ALL
 SELECT invchead_id AS id,
        35 AS type,
        invchead_invcnumber::text AS subtype,
-       3 AS section,
+       4 AS section,
        <? value("invoices") ?> AS section_qtdisplayrole,
        invchead_invcnumber::text AS name,
        CASE WHEN (invchead_posted) THEN
@@ -775,7 +775,7 @@ UNION ALL
 SELECT invcitem_id AS id, 
        37 AS type,
        invchead_invcnumber::text AS subtype,
-       3 AS section,
+       4 AS section,
        <? value("invoices") ?> AS section_qtdisplayrole,
        invcitem_linenumber::text AS name, 
        CASE WHEN (invchead_posted) THEN
@@ -820,7 +820,7 @@ UNION ALL
 SELECT invchead_id AS id, 
        38 AS type,
        invchead_invcnumber::text AS subtype,
-       3 AS section,
+       4 AS section,
        <? value("invoices") ?> AS section_qtdisplayrole,
        <? value("total") ?> AS name,
        NULL AS status,
@@ -861,7 +861,7 @@ UNION ALL
 SELECT -1 AS id, 
        39 AS type,
        MAX(invchead_invcnumber::text) AS subtype,
-       3 AS section,
+       4 AS section,
        <? value("invoices") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("invoices") ?> AS name,
        NULL AS status,
@@ -906,7 +906,7 @@ UNION ALL
 SELECT DISTINCT -1 AS id, 
        40 AS type,
        '0' AS subtype,
-       4 AS section,
+       5 AS section,
        <? value("wos") ?> AS section_qtdisplayrole,
        <? value("wos") ?> AS name,
        NULL::text AS status,
@@ -945,7 +945,7 @@ UNION ALL
 SELECT wo_id AS id, 
        45 AS type,
        formatWoNumber(wo_id) AS subtype,
-       4 AS section,
+       5 AS section,
        <? value("wos") ?> AS section_qtdisplayrole,
        formatWoNumber(wo_id) AS name,
        CASE WHEN (wo_status = 'O') THEN
@@ -997,7 +997,7 @@ UNION ALL
 SELECT -1 AS id, 
        49 AS type,
        MAX(formatWoNumber(wo_id)) AS subtype,
-       4 AS section,
+       5 AS section,
        <? value("wos") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("wos") ?> AS name,
        NULL AS status,
@@ -1041,7 +1041,7 @@ SELECT -1 AS id,
 SELECT DISTINCT -1 AS id, 
        50 AS type,
        '0' AS subtype,
-       5 AS section,
+       6 AS section,
        <? value("prs") ?> AS section_qtdisplayrole,
        <? value("prs") ?> AS name,
        NULL::text AS status,
@@ -1080,7 +1080,7 @@ UNION ALL
 SELECT pr_id AS id, 
        55 AS type,
        pr_number::text || '-' || pr_subnumber::text AS subtype,
-       5 AS section,
+       6 AS section,
        <? value("prs") ?> AS section_qtdisplayrole,
        pr_number::text || '-' || pr_subnumber::text AS name,
        <? value("open") ?> AS status, 
@@ -1122,7 +1122,7 @@ UNION ALL
 SELECT -1 AS id, 
        59 AS type,
        MAX(pr_number::text || '-' || pr_subnumber::text) AS subtype,
-       5 AS section,
+       6 AS section,
        <? value("prs") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("prs") ?> AS name,
        NULL AS status,
@@ -1164,7 +1164,7 @@ UNION ALL
 SELECT DISTINCT -1 AS id, 
        60 AS type,
        '0' AS subtype,
-       6 AS section,
+       7 AS section,
        <? value("pos") ?> AS section_qtdisplayrole,
        <? value("pos") ?> AS name,
        NULL::text AS status,
@@ -1203,7 +1203,7 @@ UNION ALL
 SELECT pohead_id AS id,
        65 AS type,
        pohead_number::text AS subtype,
-       6 AS section,
+       7 AS section,
        <? value("pos") ?> AS section_qtdisplayrole,
        pohead_number::text AS name,
        CASE WHEN (pohead_status = 'U') THEN
@@ -1250,7 +1250,7 @@ UNION ALL
 SELECT poitem_id AS id, 
        67 AS type,
        pohead_number::text AS subtype,
-       6 AS section,
+       7 AS section,
        <? value("pos") ?> AS section_qtdisplayrole,
        poitem_linenumber::text AS name, 
        CASE WHEN (poitem_status = 'U') THEN
@@ -1298,7 +1298,7 @@ UNION ALL
 SELECT pohead_id AS id, 
        68 AS type,
        pohead_number::text AS subtype,
-       6 AS section,
+       7 AS section,
        <? value("pos") ?> AS section_qtdisplayrole,
        <? value("total") ?> AS name,
        NULL AS status,
@@ -1339,7 +1339,7 @@ UNION ALL
 SELECT -1 AS id, 
        69 AS type,
        MAX(pohead_number::text) AS subtype,
-       6 AS section,
+       7 AS section,
        <? value("sos") ?> AS section_qtdisplayrole,
        <? value("total") ?> || ' ' || <? value("pos") ?> AS name,
        NULL AS status,
index c68cc92..ec14474 100644 (file)
@@ -38,7 +38,7 @@ SELECT itemsite_id, reorderlevel,
                 ib.*,
                 ((bomdata_qtyreq::NUMERIC * <? value("buildQty") ?>) * (1 + bomdata_scrap::NUMERIC)) AS pendalloc,
                 qtyAllocated(itemsite_id, DATE(<? value("buildDate") ?>)) AS totalalloc,
-                noNeg(itemsite_qtyonhand) AS qoh,
+                noNeg(qtyAvailable(itemsite_id)) AS qoh,
                 qtyOrdered(itemsite_id, DATE(<? value("buildDate") ?>)) AS ordered
            FROM indentedBOM(<? value("item_id") ?>,
                             getActiveRevId('BOM', <? value("item_id") ?>),
@@ -77,7 +77,7 @@ FROM ( SELECT itemsite_id, bomitem_seqnumber, item_number,
               ((itemuomtouom(bomitem_item_id, bomitem_uom_id, NULL,
                             (bomitem_qtyfxd + bomitem_qtyper * <? value("buildQty") ?>) * (1 + bomitem_scrap)))) AS pendalloc,
               qtyAllocated(itemsite_id, DATE(<? value("buildDate") ?>)) AS totalalloc,
-              noNeg(itemsite_qtyonhand) AS qoh,
+              noNeg(qtyAvailable(itemsite_id)) AS qoh,
               qtyOrdered(itemsite_id, DATE(<? value("buildDate") ?>)) AS ordered,
               CASE WHEN(itemsite_useparams) THEN itemsite_reorderlevel ELSE 0.0 END AS reorderlevel
        FROM itemsite, item, bomitem(<? value("item_id") ?>), uom
index 2859c48..b679d8e 100644 (file)
@@ -51,8 +51,12 @@ FROM (
                  (ipsitem_price * itemuomtouomratio(<? value('item_id') ?>, NULL, ipsitem_price_uom_id)) * iteminvpricerat(ipsitem_item_id)
                 WHEN (ipsitem_type = 'D') THEN
                  noNeg(<? value('item_listprice') ?> - (<? value('item_listprice') ?> * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount)
+                WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups') AND fetchMetricBool('WholesalePriceCosting')) THEN
+                 (<? value('item_listcost') ?> / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups')) THEN
                  (<? value('item_unitcost') ?> / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
+                WHEN (ipsitem_type = 'M' AND fetchMetricBool('WholesalePriceCosting')) THEN
+                 (<? value('item_listcost') ?> + (<? value('item_listcost') ?> * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 WHEN (ipsitem_type = 'M') THEN
                  (<? value('item_unitcost') ?> + (<? value('item_unitcost') ?> * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 ELSE 0.00
@@ -101,11 +105,16 @@ FROM (
                 ELSE ipsitem_qtybreak
            END AS invqty,
            ipsitem_qtybreak AS qtybreak,
-           CASE WHEN ipsitem_type = 'N' THEN (ipsitem_price * itemuomtouomratio(<? value('item_id') ?>, NULL, ipsitem_price_uom_id)) *
-                                              iteminvpricerat(ipsitem_item_id)
-                WHEN ipsitem_type = 'D' THEN noNeg(<? value('item_listprice') ?> - (<? value('item_listprice') ?> * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount)
+           CASE WHEN ipsitem_type = 'N' THEN
+                 (ipsitem_price * itemuomtouomratio(<? value('item_id') ?>, NULL, ipsitem_price_uom_id)) * iteminvpricerat(ipsitem_item_id)
+                WHEN ipsitem_type = 'D' THEN
+                 noNeg(<? value('item_listprice') ?> - (<? value('item_listprice') ?> * ipsitem_discntprcnt) - ipsitem_fixedamtdiscount)
+                WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups') AND fetchMetricBool('WholesalePriceCosting')) THEN
+                 (<? value('item_listcost') ?> / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 WHEN ((ipsitem_type = 'M') AND fetchMetricBool('Long30Markups')) THEN
                  (<? value('item_unitcost') ?> / (1.0 - ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
+                WHEN (ipsitem_type = 'M' AND fetchMetricBool('WholesalePriceCosting')) THEN
+                 (<? value('item_listcost') ?> + (<? value('item_listcost') ?> * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 WHEN (ipsitem_type = 'M') THEN
                  (<? value('item_unitcost') ?> + (<? value('item_unitcost') ?> * ipsitem_discntprcnt) + ipsitem_fixedamtdiscount)
                 ELSE 0.00
index 2954e7b..781516f 100644 (file)
@@ -1,12 +1,12 @@
 -- Group: projects
 -- Name:  detail
--- Notes: 
+-- Notes:
 --        Copyright (c) 1999-2013 by OpenMFG LLC, d/b/a xTuple.
 --        See www.xtuple.com/CPAL for the full text of the software license.
---        
+--
 --        xTuple version 4.2.0 - Modified to significantly amend the display of this screen and its filters.
 --        xTuple version 4.3.0 - Add Incidents to hierarchy display
-SELECT *, 
+SELECT *,
   formatQty(qty) AS f_qty,
   formatMoney(value) AS f_value,
   'curr' AS qty_xtnumericrole,
@@ -21,7 +21,7 @@ SELECT prj_id AS id,
        prj_id AS project,
        NULL  AS section_qtdisplayrole,
        prj_number AS name,
-       CASE                         
+       CASE
            WHEN prj_status = 'C' THEN <? value('complete') ?>
            WHEN prj_status = 'O' THEN <? value('inprocess') ?>
            WHEN prj_status = 'P' THEN <? value('planning') ?>
@@ -31,7 +31,7 @@ SELECT prj_id AS id,
        prj_owner_username,
        prj_name AS item,
        firstline(prj_descrip) AS descrip,
-       crmacct_name AS customer, 
+       crmacct_name AS customer,
        cntct_name AS contact,
        addr_city AS city,
        addr_state AS state,
@@ -48,8 +48,8 @@ SELECT prj_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-       CASE WHEN (prj_status = 'O' AND prj_due_date < current_date) THEN 'red' 
-         WHEN (prj_status = 'O' AND prj_due_date BETWEEN current_date AND current_date + (fetchmetricvalue('ProjectDueDateWarning')||' days')::interval) THEN 'orange' 
+       CASE WHEN (prj_status = 'O' AND prj_due_date < current_date) THEN 'red'
+         WHEN (prj_status = 'O' AND prj_due_date BETWEEN current_date AND current_date + (fetchmetricvalue('ProjectDueDateWarning')||' days')::interval) THEN 'orange'
          END AS due_qtforegroundrole,
        0 AS xtindentrole
   FROM prj()
@@ -59,10 +59,10 @@ SELECT prj_id AS id,
   LEFT OUTER JOIN addr ON (cntct_addr_id=addr_id)
 
  WHERE (1=1 )
+
 UNION ALL
 ----- TASKS -----
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        3 AS type,
        '0' AS subtype,
        1 AS section,
@@ -92,7 +92,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
     FROM prjtask
@@ -105,7 +105,7 @@ SELECT prjtask_id AS id,
        prjtask_prj_id AS project,
        NULL AS section_qtdisplayrole,
        prjtask_number AS name,
-       CASE                         
+       CASE
            WHEN prjtask_status = 'C' THEN <? value('complete') ?>
            WHEN prjtask_status = 'O' THEN <? value('inprocess') ?>
            WHEN prjtask_status = 'P' THEN <? value('planning') ?>
@@ -132,8 +132,8 @@ SELECT prjtask_id AS id,
        prjtask_exp_budget AS exp_budget,
        prjtask_exp_actual AS exp_actual,
        (prjtask_exp_budget-prjtask_exp_actual) AS exp_balance,
-       CASE WHEN (prjtask_status = 'O' AND prjtask_due_date < current_date) THEN 'red' 
-         WHEN (prjtask_status = 'O' AND prjtask_due_date BETWEEN current_date AND current_date + (fetchmetricvalue('ProjectDueDateWarning')||' days')::interval) THEN 'orange' 
+       CASE WHEN (prjtask_status = 'O' AND prjtask_due_date < current_date) THEN 'red'
+         WHEN (prjtask_status = 'O' AND prjtask_due_date BETWEEN current_date AND current_date + (fetchmetricvalue('ProjectDueDateWarning')||' days')::interval) THEN 'orange'
          END AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM prjtask
@@ -149,7 +149,7 @@ SELECT prjtask_id AS id,
 
 UNION ALL
 ----- INCIDENTS -----
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        100 AS type,
        '0' AS subtype,
        1 AS section,
@@ -179,7 +179,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
     FROM incdt
@@ -192,11 +192,11 @@ SELECT incdt_id AS id,
        incdt_prj_id AS project,
        NULL AS section_qtdisplayrole,
        incdt_number::text AS name,
-       CASE                         
+       CASE
            WHEN incdt_status = 'L' THEN <? value('closed') ?>
            WHEN incdt_status = 'N' THEN <? value('new') ?>
            WHEN incdt_status = 'F' THEN <? value('feedback') ?>
-           WHEN incdt_status = 'A' THEN <? value('assigned') ?>        
+           WHEN incdt_status = 'A' THEN <? value('assigned') ?>
            WHEN incdt_status = 'R' THEN <? value('resolved') ?>
            WHEN incdt_status = 'C' THEN <? value('confirmed') ?>
        END AS status,
@@ -232,12 +232,12 @@ SELECT incdt_id AS id,
  WHERE (1=1 )
  GROUP BY incdt_id, incdt_prj_id, incdt_number, crmacct_number, crmacct_name, addr.addr_city, addr.addr_state, cntct_name, incdt_number, incdt_status, incdt_assigned_username, incdt_owner_username, incdt_number, incdt_summary
 <? endif ?>
-    
+
 <? if exists("showSo") ?>
 UNION ALL
 
 ----- QUOTES -----
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        10 AS type,
        '0' AS subtype,
        1 AS section,
@@ -256,7 +256,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
-       NULL::numeric AS value, 
+       NULL::numeric AS value,
        NULL::date AS due,
        NULL::date AS assigned,
        NULL::date AS started,
@@ -267,7 +267,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
   FROM quhead
@@ -275,14 +275,14 @@ SELECT DISTINCT -1 AS id,
  WHERE (1=1)
 UNION ALL
 
-SELECT quhead_id AS id, 
+SELECT quhead_id AS id,
        15 AS type,
        quhead_number AS subtype,
        1 AS section,
        prj_id AS project,
        <? value("quotes") ?> AS section_qtdisplayrole,
        quhead_number AS name,
-       CASE WHEN (quhead_status = 'C') THEN 
+       CASE WHEN (quhead_status = 'C') THEN
          <? value("converted") ?>
             WHEN (quhead_status = 'X') THEN
          <? value("canceled") ?>
@@ -299,7 +299,7 @@ SELECT quhead_id AS id,
        cust_name AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        NULL AS value,
@@ -313,7 +313,7 @@ SELECT quhead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM quhead
@@ -325,14 +325,14 @@ GROUP BY prj_id, quhead_id, quhead_number, quhead_status, quhead_expire, quhead_
 
 UNION ALL
 
-SELECT quitem_id AS id, 
+SELECT quitem_id AS id,
        17 AS type,
        quhead_number AS subtype,
        1 AS section,
        prj_id AS project,
        <? value("quotes") ?> AS section_qtdisplayrole,
-       quitem_linenumber::text AS name, 
-       CASE WHEN (quhead_status = 'C') THEN 
+       quitem_linenumber::text AS name,
+       CASE WHEN (quhead_status = 'C') THEN
          <? value("converted") ?>
             WHEN (quhead_status = 'X') THEN
          <? value("canceled") ?>
@@ -349,7 +349,7 @@ SELECT quitem_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        quitem_qtyord,
        uom_name AS uom,
        (quitem_qtyord * quitem_qty_invuomratio) * (quitem_price / quitem_price_invuomratio) AS value,
@@ -362,7 +362,7 @@ SELECT quitem_id AS id,
        NULL::numeric AS hrs_balance,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
-       NULL::numeric AS exp_balance, 
+       NULL::numeric AS exp_balance,
        NULL::text AS due_qtforegroundrole,
        3 AS xtindentrole
   FROM quhead
@@ -375,7 +375,7 @@ SELECT quitem_id AS id,
 
 UNION ALL
 
-SELECT quhead_id AS id, 
+SELECT quhead_id AS id,
        18 AS type,
        quhead_number AS subtype,
        1 AS section,
@@ -391,7 +391,7 @@ SELECT quhead_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((quitem_qtyord * quitem_qty_invuomratio) * (quitem_price / quitem_price_invuomratio)) AS value,
@@ -405,7 +405,7 @@ SELECT quhead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM quhead
@@ -416,7 +416,7 @@ GROUP BY prj_id, quhead_id, quhead_number
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        19 AS type,
        MAX(quhead_number) AS subtype,
        1 AS section,
@@ -432,7 +432,7 @@ SELECT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((quitem_qtyord * quitem_qty_invuomratio) * (quitem_price / quitem_price_invuomratio)) AS value,
@@ -446,7 +446,7 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM quhead
@@ -458,7 +458,7 @@ SELECT -1 AS id,
 UNION ALL
 
 ------ SALES ORDERS ------
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        20 AS type,
        '0' AS subtype,
        2 AS section,
@@ -474,7 +474,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
        NULL::numeric AS value,
@@ -488,7 +488,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
   FROM cohead
@@ -497,14 +497,14 @@ SELECT DISTINCT -1 AS id,
 
 UNION ALL
 
-SELECT cohead_id AS id, 
+SELECT cohead_id AS id,
        25 AS type,
        cohead_number::text AS subtype,
        2 AS section,
        prj_id AS project,
        <? value("sos") ?> AS section_qtdisplayrole,
        cohead_number::text AS name,
-      COALESCE((SELECT 
+      COALESCE((SELECT
                   CASE WHEN (coitem_status = 'O') THEN
                     <? value("open") ?>
                        WHEN (coitem_status = 'C') THEN
@@ -512,9 +512,9 @@ SELECT cohead_id AS id,
                       ELSE
                     <? value("canceled") ?>
                   END
-                FROM 
+                FROM
                (SELECT coitem_status,
-                   CASE 
+                   CASE
                      WHEN (coitem_status = 'O') THEN 1
                      WHEN (coitem_status = 'C') then 2
                      ELSE  3
@@ -532,7 +532,7 @@ SELECT cohead_id AS id,
        cust_name AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        NULL AS value,
@@ -546,7 +546,7 @@ SELECT cohead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM cohead
@@ -559,13 +559,13 @@ GROUP BY prj_id,cohead_id, cohead_number, shipto_num, shipto_name, cust_name
 
 UNION ALL
 
-SELECT coitem_id AS id, 
+SELECT coitem_id AS id,
        27 AS type,
        cohead_number::text AS subtype,
        2 AS section,
        prj_id AS project,
        <? value("sos") ?> AS section_qtdisplayrole,
-       coitem_linenumber::text AS name, 
+       coitem_linenumber::text AS name,
        CASE WHEN (coitem_status = 'O') THEN
          <? value("open") ?>
             WHEN (coitem_status = 'C') THEN
@@ -581,7 +581,7 @@ SELECT coitem_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        coitem_qtyord,
        uom_name AS uom,
        (coitem_qtyord * coitem_qty_invuomratio) * (coitem_price / coitem_price_invuomratio) AS value,
@@ -595,7 +595,7 @@ SELECT coitem_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        3 AS xtindentrole
   FROM cohead
@@ -608,7 +608,7 @@ SELECT coitem_id AS id,
 
 UNION ALL
 
-SELECT cohead_id AS id, 
+SELECT cohead_id AS id,
        28 AS type,
        cohead_number::text AS subtype,
        2 AS section,
@@ -624,7 +624,7 @@ SELECT cohead_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((coitem_qtyord * coitem_qty_invuomratio) * (coitem_price / coitem_price_invuomratio)) AS value,
@@ -638,7 +638,7 @@ SELECT cohead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM cohead
@@ -649,7 +649,7 @@ GROUP BY prj_id,cohead_id, cohead_number
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        29 AS type,
        MAX(cohead_number::text) AS subtype,
        2 AS section,
@@ -665,7 +665,7 @@ SELECT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((coitem_qtyord * coitem_qty_invuomratio) * (coitem_price / coitem_price_invuomratio)) AS value,
@@ -679,7 +679,7 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-               
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM cohead
@@ -687,11 +687,11 @@ SELECT -1 AS id,
     JOIN coitem ON (coitem_cohead_id = cohead_id)
  WHERE (1=1)
  GROUP BY prj_id
+
 UNION ALL
 
 ------ INVOICES -------
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        30 AS type,
        '0' AS subtype,
        3 AS section,
@@ -707,7 +707,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
        NULL::numeric AS value,
@@ -721,7 +721,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
   FROM invchead
@@ -749,7 +749,7 @@ SELECT invchead_id AS id,
        cust_name AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        NULL AS value,
@@ -763,7 +763,7 @@ SELECT invchead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM invchead
@@ -777,13 +777,13 @@ GROUP BY prj_id,invchead_id, invchead_invcnumber, shipto_num, shipto_name, invch
 
 UNION ALL
 
-SELECT invcitem_id AS id, 
+SELECT invcitem_id AS id,
        37 AS type,
        invchead_invcnumber::text AS subtype,
        3 AS section,
        prj_id AS project,
        <? value("invoices") ?> AS section_qtdisplayrole,
-       invcitem_linenumber::text AS name, 
+       invcitem_linenumber::text AS name,
        CASE WHEN (invchead_posted) THEN
          <? value("posted") ?>
        ELSE <? value("unposted") ?>
@@ -796,7 +796,7 @@ SELECT invcitem_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        invcitem_billed AS qty,
        uom_name AS uom,
        (invcitem_billed * invcitem_qty_invuomratio) * (invcitem_price / invcitem_price_invuomratio) AS value,
@@ -810,7 +810,7 @@ SELECT invcitem_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        3 AS xtindentrole
   FROM invchead
@@ -822,7 +822,7 @@ SELECT invcitem_id AS id,
 
 UNION ALL
 
-SELECT invchead_id AS id, 
+SELECT invchead_id AS id,
        38 AS type,
        invchead_invcnumber::text AS subtype,
        3 AS section,
@@ -838,7 +838,7 @@ SELECT invchead_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((invcitem_billed * invcitem_qty_invuomratio) * (invcitem_price / invcitem_price_invuomratio)) AS value,
@@ -852,7 +852,7 @@ SELECT invchead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-       
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM invchead
@@ -863,7 +863,7 @@ GROUP BY prj_id,invchead_id, invchead_invcnumber
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        39 AS type,
        MAX(invchead_invcnumber::text) AS subtype,
        3 AS section,
@@ -879,7 +879,7 @@ SELECT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM((invcitem_billed * invcitem_qty_invuomratio) * (invcitem_price / invcitem_price_invuomratio)) AS value,
@@ -893,7 +893,7 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM invchead
@@ -901,14 +901,14 @@ SELECT -1 AS id,
     JOIN invcitem ON (invcitem_invchead_id = invchead_id)
  WHERE (1=1)
  GROUP BY prj_id
-<? endif ?>  
+
+<? endif ?>
 
 <? if exists("showWo") ?>
 UNION ALL
 
 ------ WORK ORDERS -------
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        40 AS type,
        '0' AS subtype,
        4 AS section,
@@ -924,7 +924,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
        NULL::numeric AS value,
@@ -938,16 +938,16 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
-  FROM wo 
+  FROM wo
   JOIN prj() ON (wo_prj_id=prj_id)
  WHERE (1=1)
 
 UNION ALL
 
-SELECT wo_id AS id, 
+SELECT wo_id AS id,
        45 AS type,
        formatWoNumber(wo_id) AS subtype,
        4 AS section,
@@ -973,7 +973,7 @@ SELECT wo_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        wo_qtyord AS qty,
        uom_name AS uom,
        wo_postedvalue AS value,
@@ -987,7 +987,7 @@ SELECT wo_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-       
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM wo
@@ -999,7 +999,7 @@ SELECT wo_id AS id,
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        49 AS type,
        MAX(formatWoNumber(wo_id)) AS subtype,
        4 AS section,
@@ -1015,7 +1015,7 @@ SELECT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM(wo_postedvalue) AS value,
@@ -1029,7 +1029,7 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM wo
@@ -1043,7 +1043,7 @@ SELECT -1 AS id,
 <? if exists("showPo") ?>
  UNION ALL
 ------ PURCHASE REQUESTS ------
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        50 AS type,
        '0' AS subtype,
        5 AS section,
@@ -1059,7 +1059,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
        NULL::numeric AS value,
@@ -1073,7 +1073,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
   FROM pr
@@ -1082,14 +1082,14 @@ SELECT DISTINCT -1 AS id,
 
 UNION ALL
 
-SELECT pr_id AS id, 
+SELECT pr_id AS id,
        55 AS type,
        pr_number::text || '-' || pr_subnumber::text AS subtype,
        5 AS section,
        prj_id AS project,
        <? value("prs") ?> AS section_qtdisplayrole,
        pr_number::text || '-' || pr_subnumber::text AS name,
-       <? value("open") ?> AS status, 
+       <? value("open") ?> AS status,
        NULL::text AS project_type,
        NULL::text AS prj_username,
        NULL::text AS prj_owner_username,
@@ -1098,7 +1098,7 @@ SELECT pr_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        pr_qtyreq AS qty,
        uom_name AS uom,
        stdcost(item_id) * pr_qtyreq AS value,
@@ -1112,7 +1112,7 @@ SELECT pr_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM pr
@@ -1124,7 +1124,7 @@ SELECT pr_id AS id,
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        59 AS type,
        MAX(pr_number::text || '-' || pr_subnumber::text) AS subtype,
        5 AS section,
@@ -1137,10 +1137,10 @@ SELECT -1 AS id,
        NULL::text AS prj_owner_username,
        NULL::text AS item,
        NULL::text AS descrip,
-       NULL::text AS customer,       
+       NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM(stdcost(item_id) * pr_qtyreq) AS value,
@@ -1154,7 +1154,7 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM pr
@@ -1163,11 +1163,11 @@ SELECT -1 AS id,
     JOIN item ON (itemsite_item_id = item_id)
  WHERE (1=1)
  GROUP BY prj_id
+
 UNION ALL
 
 ------ PURCHASE ORDERS ------
-SELECT DISTINCT -1 AS id, 
+SELECT DISTINCT -1 AS id,
        60 AS type,
        '0' AS subtype,
        6 AS section,
@@ -1183,7 +1183,7 @@ SELECT DISTINCT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL::numeric AS qty,
        NULL::text AS uom,
        NULL::numeric AS value,
@@ -1197,7 +1197,7 @@ SELECT DISTINCT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        1 AS xtindentrole
   FROM poitem
@@ -1228,7 +1228,7 @@ SELECT pohead_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL AS uom,
        NULL AS value,
@@ -1242,7 +1242,7 @@ SELECT pohead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM pohead
@@ -1253,13 +1253,13 @@ GROUP BY prj_id,pohead_id, pohead_number, pohead_freight, pohead_status
 
 UNION ALL
 
-SELECT poitem_id AS id, 
+SELECT poitem_id AS id,
        67 AS type,
        pohead_number::text AS subtype,
        6 AS section,
        prj_id AS project,
        <? value("pos") ?> AS section_qtdisplayrole,
-       poitem_linenumber::text AS name, 
+       poitem_linenumber::text AS name,
        CASE WHEN (poitem_status = 'U') THEN
          <? value("unreleased") ?>
             WHEN (poitem_status = 'O') THEN
@@ -1275,7 +1275,7 @@ SELECT poitem_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        poitem_qty_ordered,
        poitem_vend_uom AS uom,
        (poitem_qty_ordered * poitem_unitprice) AS value,
@@ -1289,7 +1289,7 @@ SELECT poitem_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        3 AS xtindentrole
   FROM pohead
@@ -1301,7 +1301,7 @@ SELECT poitem_id AS id,
 
 UNION ALL
 
-SELECT pohead_id AS id, 
+SELECT pohead_id AS id,
        68 AS type,
        pohead_number::text AS subtype,
        6 AS section,
@@ -1317,7 +1317,7 @@ SELECT pohead_id AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM(poitem_qty_ordered * poitem_unitprice) AS value,
@@ -1331,7 +1331,7 @@ SELECT pohead_id AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM pohead
@@ -1342,7 +1342,7 @@ GROUP BY prj_id,pohead_id, pohead_number
 
 UNION ALL
 
-SELECT -1 AS id, 
+SELECT -1 AS id,
        69 AS type,
        MAX(pohead_number::text) AS subtype,
        6 AS section,
@@ -1358,7 +1358,7 @@ SELECT -1 AS id,
        NULL::text AS customer,
        NULL::text AS contact,
        NULL::text AS city,
-       NULL::text AS state,       
+       NULL::text AS state,
        NULL AS qty,
        NULL::text AS uom,
        SUM(poitem_qty_ordered * poitem_unitprice) AS value,
@@ -1372,14 +1372,14 @@ SELECT -1 AS id,
        NULL::numeric AS exp_budget,
        NULL::numeric AS exp_actual,
        NULL::numeric AS exp_balance,
-        
+
        NULL::text AS due_qtforegroundrole,
        2 AS xtindentrole
   FROM pohead
     JOIN poitem ON (poitem_pohead_id = pohead_id)
     JOIN prj() ON (poitem_prj_id=prj_id)
  WHERE (1=1)
- GROUP BY prj_id 
+ GROUP BY prj_id
 
 <? endif ?>
 
@@ -1394,15 +1394,15 @@ WHERE (true)
 <? if exists("username") ?>
   AND (prj_username=<? value("username") ?> OR prj_owner_username=<? value("username") ?>)
 <? endif ?>
-<? if exists("assigned_username") ?> 
-  AND (prj_username=<? value("assigned_username") ?>) 
+<? if exists("assigned_username") ?>
+  AND (prj_username=<? value("assigned_username") ?>)
 <? elseif exists("assigned_usr_pattern") ?>
-  AND (prj_username ~ <? value("assigned_usr_pattern") ?>) 
+  AND (prj_username ~ <? value("assigned_usr_pattern") ?>)
 <? endif ?>
-<? if exists("owner_username") ?> 
+<? if exists("owner_username") ?>
   AND (prj_owner_username=<? value("owner_username") ?>)
 <? elseif exists("owner_usr_pattern") ?>
-  AND (prj_owner_username ~ <? value("owner_usr_pattern") ?>) 
+  AND (prj_owner_username ~ <? value("owner_usr_pattern") ?>)
 <? endif ?>
 <? if exists("crmacct_id") ?>
   AND project IN (SELECT prj_id FROM prj WHERE (prj_crmacct_id=<? value("crmacct_id") ?>))
@@ -1455,12 +1455,8 @@ WHERE (true)
   AND project IN (SELECT wo_prj_id FROM wo WHERE wo_id=<? value("wo_id") ?>)
 <? endif ?>
 <? if exists("pohead_id") ?>
-  AND project IN (SELECT poitem_prj_id FROM pohead JOIN poitem ON (pohead_id=poitem_pohead_id) 
+  AND project IN (SELECT poitem_prj_id FROM pohead JOIN poitem ON (pohead_id=poitem_pohead_id)
                        WHERE pohead_id=<? value("pohead_id") ?>)
 <? endif ?>
-<? if exists("prjtype_id") ?>
-  AND project IN (SELECT prj_id FROM prj WHERE prj_prjtype_id = <? value("prjtype_id") ?>)
-<? endif ?>
-
 
 ORDER BY project, section, subtype, type, id;
index 7791311..4edd402 100644 (file)
@@ -105,5 +105,23 @@ WHERE (true)
 <? if exists("id") ?>
   AND (prj_id=<? value("id") ?>)
 <? endif ?>
+<? if exists("prj_id") ?>
+  AND (prj_id=<? value("prj_id") ?>)
+<? endif ?>
+<? if exists("project_task") ?>
+  AND prj_id IN (SELECT DISTINCT prjtask_prj_id FROM prjtask where ((prjtask_number ~* <? value("project_task") ?>)
+                                               OR (prjtask_name ~* <? value("project_task") ?>)
+                                               OR (prjtask_descrip ~* <? value("project_task") ?>)))
+<? endif ?>
+<? if exists("cohead_id") ?>
+  AND prj_id IN (SELECT cohead_prj_id FROM cohead where cohead_id=<? value("cohead_id") ?>)
+<? endif ?>
+<? if exists("wo_id") ?>
+  AND prj_id IN (SELECT wo_prj_id FROM wo WHERE wo_id=<? value("wo_id") ?>)
+<? endif ?>
+<? if exists("pohead_id") ?>
+  AND prj_id IN (SELECT poitem_prj_id FROM pohead JOIN poitem ON (pohead_id=poitem_pohead_id)
+                       WHERE pohead_id=<? value("pohead_id") ?>)
+<? endif ?>
 <? literal("charClause") ?>
 ORDER BY prj_number;
\ No newline at end of file
index 840c413..5ca4799 100644 (file)
@@ -5,6 +5,7 @@
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT pr_id, itemsite_id, itemsite_qtyonhand, itemsite_reorderlevel,
+       qtyNetable(itemsite_id) AS netableqoh, qtyNetable(itemsite_id, FALSE) AS nonnetableqoh,
        item_number, (item_descrip1 || ' ' || item_descrip2) AS description,
        pr.*,
        CASE WHEN (pr_order_type='W') THEN ('W/O ' || ( SELECT formatWoNumber(womatl_wo_id)
index cd80d69..8862e39 100644 (file)
@@ -159,10 +159,15 @@ SELECT itemsite_id, detail,warehous_code,
        defaultlocation,
        reorderlevel, formatQty(reorderlevel) AS f_reorderlevel,
        qoh, formatQty(qoh) AS f_qoh,
-       nnqoh, formatQty(nnqoh) AS f_nnqoh,
-       CASE WHEN (itemsite_loccntrl) THEN nnqoh END AS f_nnqoh,
+       availqoh, formatQty(availqoh) AS f_availqoh,
+       nonavailqoh, formatQty(nonavailqoh) AS f_nonavailqoh,
+       netqoh, formatQty(netqoh) AS f_netqoh,
+       nonnetqoh, formatQty(nonnetqoh) AS f_nonnetqoh,
        cost, (cost * qoh) AS value,
-       CASE WHEN (itemsite_loccntrl) THEN (cost * nnqoh) END AS nnvalue,
+       (cost * availqoh) AS availvalue,
+       (cost * nonavailqoh) AS nonavailvalue,
+       (cost * netqoh) AS netvalue,
+       (cost * nonnetqoh) AS nonnetvalue,
        CASE WHEN(itemsite_costmethod='A') THEN 'Average'
             WHEN(itemsite_costmethod='S') THEN 'Standard'
             WHEN(itemsite_costmethod='J') THEN 'Job'
@@ -171,7 +176,10 @@ SELECT itemsite_id, detail,warehous_code,
        END AS costmethod,
   <? if exists("showValue") ?>
        formatMoney(cost) AS f_cost, (cost * qoh) AS f_value,
-       CASE WHEN (itemsite_loccntrl) THEN (cost * nnqoh) END AS f_nnvalue,
+       formatMoney(cost * availqoh) AS f_availvalue,
+       formatMoney(cost * nonavailqoh) AS f_nonavailvalue,
+       formatMoney(cost * netqoh) AS f_netvalue,
+       formatMoney(cost * nonnetqoh) AS f_nonnetvalue,
        CASE WHEN(itemsite_costmethod='A') THEN 'Average'
             WHEN(itemsite_costmethod='S') THEN 'Standard'
             WHEN(itemsite_costmethod='J') THEN 'Job'
@@ -181,16 +189,34 @@ SELECT itemsite_id, detail,warehous_code,
   <? endif ?>
        'qty' AS reorderlevel_xtnumericrole,
        'qty' AS qoh_xtnumericrole,
-       'qty' AS f_nnqoh_xtnumericrole,
+       'qty' AS availqoh_xtnumericrole,
+       'qty' AS nonavailqoh_xtnumericrole,
+       'qty' AS netqoh_xtnumericrole,
+       'qty' AS nonnetqoh_xtnumericrole,
        0 AS qoh_xttotalrole,
-       0 AS nnqoh_xttotalrole,
+       0 AS availqoh_xttotalrole,
+       0 AS nonavailqoh_xttotalrole,
+       0 AS netqoh_xttotalrole,
+       0 AS nonnetqoh_xttotalrole,
        'cost' AS cost_xtnumericrole,
        'curr' AS value_xtnumericrole,
-       'curr' AS nnvalue_xtnumericrole,
+       'curr' AS availvalue_xtnumericrole,
+       'curr' AS nonavailvalue_xtnumericrole,
+       'curr' AS netvalue_xtnumericrole,
+       'curr' AS nonnetvalue_xtnumericrole,
        0 AS value_xttotalrole,
-       0 AS nnvalue_xttotalrole,
-       <? value("na") ?> AS nnqoh_xtnullrole,
-       <? value("na") ?> AS nnvalue_xtnullrole,
+       0 AS availvalue_xttotalrole,
+       0 AS nonavailvalue_xttotalrole,
+       0 AS netvalue_xttotalrole,
+       0 AS nonnetvalue_xttotalrole,
+       <? value("na") ?> AS availqoh_xtnullrole,
+       <? value("na") ?> AS nonavailqoh_xtnullrole,
+       <? value("na") ?> AS availvalue_xtnullrole,
+       <? value("na") ?> AS nonavailvalue_xtnullrole,
+       <? value("na") ?> AS netqoh_xtnullrole,
+       <? value("na") ?> AS nonnetqoh_xtnullrole,
+       <? value("na") ?> AS netvalue_xtnullrole,
+       <? value("na") ?> AS nonnetvalue_xtnullrole,
        CASE WHEN (qoh < 0) THEN 'error' END AS qoh_qtforegroundrole,
        CASE WHEN (reorderlevel > qoh) THEN 'warning' END AS qoh_qtforegroundrole
 FROM (
@@ -205,10 +231,16 @@ FROM (
              CASE WHEN(itemsite_useparams) THEN itemsite_reorderlevel ELSE 0.0 END AS reorderlevel,
   <? if exists("asOf") ?>
              COALESCE(invbal_qoh_ending,0) AS qoh,
-             COALESCE(invbal_nn_ending,0) AS nnqoh,
+             COALESCE(invbal_qoh_ending,0) AS availqoh,
+             COALESCE(invbal_nn_ending,0) AS nonavailqoh,
+             COALESCE(invbal_qoh_ending,0) AS netqoh,
+             COALESCE(invbal_nn_ending,0) AS nonnetqoh,
   <? else ?>
              itemsite_qtyonhand AS qoh,
-             itemsite_nnqoh AS nnqoh,
+             qtyAvailable(itemsite_id) AS availqoh,
+             qtyAvailable(itemsite_id, FALSE) AS nonavailqoh,
+             qtyNetable(itemsite_id) AS netqoh,
+             qtyNetable(itemsite_id, FALSE) AS nonnetqoh,
   <? endif ?>
   <? if exists("useStandardCosts") ?>
              stdcost(item_id) AS cost
@@ -219,8 +251,8 @@ FROM (
              COALESCE((invbal_value_ending / CASE WHEN(invbal_qoh_ending=0) THEN 1
                                                   ELSE invbal_qoh_ending END),0) AS cost
     <? else ?>
-             (itemsite_value / CASE WHEN((itemsite_qtyonhand + itemsite_nnqoh)=0) THEN 1
-                                    ELSE (itemsite_qtyonhand + itemsite_nnqoh) END) AS cost
+             (itemsite_value / CASE WHEN(itemsite_qtyonhand=0) THEN 1
+                                    ELSE itemsite_qtyonhand END) AS cost
     <? endif ?>
   <? endif ?>
       FROM item, whsinfo, classcode, uom, costcat, itemsite
index 7d0b90a..a4239d8 100644 (file)
@@ -7,7 +7,7 @@
 SELECT itemsite_id, itemtype, warehous_code, item_number,
        (item_descrip1 || ' ' || item_descrip2) AS itemdescrip,
        reorderdate, reorderlevel,
-       (itemsite_qtyonhand - qtyAllocated(itemsite_id, reorderdate) +
+       (qtyNetable(itemsite_id) - qtyAllocated(itemsite_id, reorderdate) +
          qtyOrdered(itemsite_id, reorderdate)) AS projavail,
        'qty' AS reorderlevel_xtnumericrole,
        'qty' AS projavail_xtnumericrole
@@ -22,9 +22,9 @@ FROM (SELECT itemsite_id,
                          <? value("lookAheadDays") ?>,
                          <? value("includePlannedOrders") ?>)
              AS reorderdate,
-             itemsite_qtyonhand, reorderlevel
+             reorderlevel
       FROM (SELECT itemsite_id, itemsite_item_id,
-                   itemsite_warehous_id, itemsite_qtyonhand,
+                   itemsite_warehous_id,
                    CASE WHEN(itemsite_useparams) THEN itemsite_reorderlevel
                      ELSE 0.0
                    END AS reorderlevel
index a5ccea5..c94d852 100644 (file)
@@ -6,7 +6,7 @@
 
 SELECT orderid, altorderid, ordertype, ordernumber, sequence, item_number,
        duedate, amount, qtyordered,  qtyreceived, balance,
-       balance AS runningavail,
+       balance AS runningavail, balance AS runningnetable,
 <? if exists("isReport") ?>
        CASE WHEN duedate = startOfTime() THEN ''
             ELSE formatDate(duedate) END AS f_duedate,
@@ -17,7 +17,9 @@ SELECT orderid, altorderid, ordertype, ordernumber, sequence, item_number,
 <? endif ?>
        notes,
        1 AS runningavail_xtrunningrole,
+       1 AS runningnetable_xtrunningrole,
        <? value("qoh") ?> AS runningavail_xtrunninginit,
+       <? value("netableqoh") ?> AS runningnetable_xtrunninginit,
        CASE WHEN late THEN 'error' END AS duedate_qtforegroundrole,
        CASE WHEN duedate = startOfTime() THEN '' END AS duedate_qtdisplayrole,
        CASE WHEN ordertype ~ <? value("plannedPo") ?> OR
index 50da06f..a18a183 100644 (file)
@@ -4,66 +4,35 @@
 --        Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 --        See www.xtuple.com/CPAL for the full text of the software license.
 
-SELECT cohist.*,
-       CASE WHEN (cohist_invcnumber='-1') THEN  <? value("credit") ?>
+SELECT *,
+       CASE WHEN (COALESCE(cohist_invcnumber, '-1') IN ('', '-1')) THEN  <? value("credit") ?>
             ELSE cohist_invcnumber
        END AS invoicenumber,
-       cust_number, cust_name, salesrep_name,
-       saletype_code, shipzone_name,
-       item_id, COALESCE(item_number, cohist_misc_descrip) AS item_number,
-       item_descrip1, (item_descrip1 || ' ' || item_descrip2) AS itemdescription,
-       warehous_code,
-       currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate) AS baseunitprice,
-       round((cohist_qtyshipped * cohist_unitprice), 2) AS extprice,
-       round((cohist_qtyshipped * currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate)), 2) AS baseextprice,
-       round((cohist_qtyshipped * cohist_unitcost), 4) AS extcost,
-       currtobase(cohist_curr_id, cohist_commission, cohist_invcdate) AS basecommission,
 <? if exists("isReport") ?>
+       formatDate(cohist_orderdate) AS f_orderdate,
        formatDate(cohist_invcdate) AS f_invcdate,
        formatQty(cohist_qtyshipped) AS f_qtyshipped,
        formatBoolYN(cohist_commissionpaid) AS f_commissionpaid,
-       formatSalesPrice(currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate)) AS f_baseunitprice,
-       formatMoney(round((cohist_qtyshipped * cohist_unitprice), 2)) AS f_extprice,
-       formatMoney(round((cohist_qtyshipped * currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate)), 2)) AS f_baseextprice,
-       formatMoney(round((cohist_qtyshipped * cohist_unitcost), 4)) AS f_extcost,
-       formatMoney(currtobase(cohist_curr_id, cohist_commission, cohist_invcdate)) AS f_basecommission,
+       formatSalesPrice(baseunitprice) AS f_baseunitprice,
+       formatMoney(extprice) AS f_extprice,
+       formatMoney(baseextprice) AS f_baseextprice,
+       formatMoney(extcost) AS f_extcost,
+       formatMoney(margin) AS f_margin,
+       formatPrcnt(marginpercent) AS f_marginpercent,
+       formatMoney(basecommission) AS f_basecommission,
 <? endif ?>
-       currConcat(cohist_curr_id) AS currAbbr,
        <? value("return") ?> AS cohist_invcdate_xtnullrole,
-       'qty' AS cohist_qtyshipped_xtnumericrole,
-       'salesprice' AS cohist_unitprice_xtnumericrole,
-       'salesprice' AS baseunitprice_xtnumericrole,
-       'curr' AS extprice_xtnumericrole,
-       'curr' AS baseextprice_xtnumericrole,
-       'cost' AS cohist_unitcost_xtnumericrole,
-       'curr' AS extcost_xtnumericrole,
-       'curr' AS cohist_commission_xtnumericrole,
-       'curr' AS basecommission_xtnumericrole,
        0 AS cohist_qtyshipped_xttotalrole,
        0 AS baseextprice_xttotalrole,
        0 AS extcost_xttotalrole,
+       0 AS margin_xttotalrole,
        0 AS basecommission_xttotalrole
-  FROM cohist JOIN custinfo ON (cust_id=cohist_cust_id)
-              JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
-              LEFT OUTER JOIN saletype ON (saletype_id=cohist_saletype_id)
-              LEFT OUTER JOIN shipzone ON (shipzone_id=cohist_shipzone_id)
 <? if exists("includeMisc") ?>
-              LEFT OUTER JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
-              LEFT OUTER JOIN site() ON (warehous_id=itemsite_warehous_id)
-              LEFT OUTER JOIN item ON (item_id=itemsite_item_id)
+  FROM saleshistorymisc
 <? else ?>
-              JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
-              JOIN site() ON (warehous_id=itemsite_warehous_id)
-              JOIN item ON (item_id=itemsite_item_id)
-<? endif ?>
-<? if exists("cohead_id") ?>
-              JOIN cohead ON (cohead_number=cohist_ordernumber)
+  FROM saleshistory
 <? endif ?>
 WHERE ( (true)
-<? if exists("includeMisc") ?>
-  AND  (COALESCE(cohist_misc_type, '') <> 'F')
-  AND  (COALESCE(cohist_misc_type, '') <> 'T')
-<? endif ?>
 <? if exists("startDate") ?>
   AND  (cohist_invcdate >= <? value("startDate") ?>)
 <? endif ?>
@@ -89,11 +58,11 @@ WHERE ( (true)
   AND  (cohist_cust_id=<? value("cust_id") ?>)
 <? endif ?>
 <? if exists("custtype_id") ?>
-  AND  (cust_custtype_id=<? value("custtype_id") ?>)
+  AND  (custtype_id=<? value("custtype_id") ?>)
 <? elseif exists("custtype_pattern") ?>
-  AND  (cust_custtype_id IN (SELECT DISTINCT custtype_id
-                             FROM custtype
-                             WHERE (custtype_code ~ <? value("custtype_pattern") ?>)))
+  AND  (custtype_id IN (SELECT DISTINCT custtype_id
+                        FROM custtype
+                        WHERE (custtype_code ~ <? value("custtype_pattern") ?>)))
 <? endif ?>
 <? if exists("by_custgrp") ?>
   AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
@@ -112,19 +81,19 @@ WHERE ( (true)
 <? endif ?>
 
 <? if exists("item_id") ?>
-  AND  (itemsite_item_id=<? value("item_id") ?>)
+  AND  (item_id=<? value("item_id") ?>)
 <? endif ?>
 <? if exists("prodcat_id") ?>
-  AND (item_prodcat_id=<? value("prodcat_id") ?>)
+  AND (prodcat_id=<? value("prodcat_id") ?>)
 <? endif ?>
 <? if exists("prodcat_pattern") ?>
-  AND (item_prodcat_id IN (SELECT DISTINCT prodcat_id
-                           FROM prodcat
-                           WHERE (prodcat_code ~ <? value("prodcat_pattern") ?>)))
+  AND (prodcat_id IN (SELECT DISTINCT prodcat_id
+                      FROM prodcat
+                      WHERE (prodcat_code ~ <? value("prodcat_pattern") ?>)))
 <? endif ?>
 
 <? if exists("warehous_id") ?>
-  AND  (itemsite_warehous_id=<? value("warehous_id") ?>)
+  AND  (warehous_id=<? value("warehous_id") ?>)
 <? endif ?>
 <? if exists("shipzone_id") ?>
   AND (cohist_shipzone_id=<? value("shipzone_id") ?>)
@@ -136,5 +105,5 @@ WHERE ( (true)
   AND (cohead_id=<? value("cohead_id") ?>)
 <? endif ?>
       )
-ORDER BY cohist_invcdate, item_number;
+ORDER BY cohist_invcdate, itemnumber;
 
index 3f06697..85a12f3 100644 (file)
@@ -59,8 +59,8 @@ SELECT coitem_id, coitem_altid, groupby,
             ELSE 1
        END AS xtindentrole,
        spplytype, ordrnumbr,
-       itemsite_qtyonhand,
-       'qty' AS itemsite_qtyonhand_xtnumericrole
+       availableqoh,
+       'qty' AS availableqoh_xtnumericrole
 <? if exists("includeReservations") ?>
        ,
        reserved,
@@ -101,8 +101,7 @@ SELECT coitem_id,
        END AS discountfromcust,
        coitem_unitcost,
        CASE WHEN (coitem_price = 0.0) THEN 0.0
-            ELSE ROUND((coitem_qtyord * coitem_qty_invuomratio) *
-                 ((coitem_price / coitem_price_invuomratio) - (coitem_unitcost / coitem_price_invuomratio)),2)
+            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)
@@ -124,11 +123,11 @@ SELECT coitem_id,
             WHEN coitem_order_type='R' THEN (pr_number || '-' || pr_subnumber)
             ELSE TEXT (' ')
        END AS ordrnumbr,
-       itemsite_qtyonhand
+       qtyAvailable(itemsite_id) AS availableqoh
 <? if exists("includeReservations") ?>
        ,
        coitem_qtyreserved AS reserved,
-       itemsite_qtyonhand - qtyreserved(itemsite_id) AS reservable
+       qtyAvailable(itemsite_id) - qtyReserved(itemsite_id) AS reservable
 <? endif?>
   FROM cohead
        JOIN coitem ON (coitem_cohead_id=cohead_id)
index 2096fa5..a92db1e 100644 (file)
@@ -5,9 +5,9 @@
 --        See www.xtuple.com/CPAL for the full text of the software license.
 
 SELECT s_itemsite_id, warehous_code, item_number, itemdescrip,
-       qtyonhand, reorderlevel, leadtime, itemsub_rank,
+       availableqoh, reorderlevel, leadtime, itemsub_rank,
        allocated, ordered, available,
-       'qty' AS qtyonhand_xtnumericrole,
+       'qty' AS availableqoh_xtnumericrole,
        'qty' AS allocated_xtnumericrole,
        'qty' AS ordered_xtnumericrole,
        'qty' AS reorderlevel_xtnumericrole,
@@ -17,14 +17,14 @@ FROM (SELECT sub.itemsite_id AS s_itemsite_id,
              warehous_code, item_number,
              (item_descrip1 || ' ' || item_descrip2) AS itemdescrip,
 <? if exists("normalize") ?>
-             (sub.itemsite_qtyonhand * itemsub_uomratio) AS qtyonhand,
+             (qtyAvailable(sub.itemsite_id) * itemsub_uomratio) AS availableqoh,
              (CASE WHEN(sub.itemsite_useparams)
                    THEN sub.itemsite_reorderlevel
                 ELSE 0.0
              END * itemsub_uomratio) AS reorderlevel,
              sub.itemsite_leadtime AS leadtime, itemsub_rank,
 <? else ?>
-             (sub.itemsite_qtyonhand) AS qtyonhand,
+             (qtyAvailable(sub.itemsite_id)) AS availableqoh,
              CASE WHEN(sub.itemsite_useparams) THEN sub.itemsite_reorderlevel
                ELSE 0.0
              END AS reorderlevel,
@@ -34,37 +34,37 @@ FROM (SELECT sub.itemsite_id AS s_itemsite_id,
   <? if exists("normalize") ?>
              (qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime) * itemsub_uomratio) AS allocated,
              (qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime) * itemsub_uomratio) AS ordered,
-             ((sub.itemsite_qtyonhand * itemsub_uomratio)
+             ((qtyAvailable(sub.itemsite_id) * itemsub_uomratio)
               + (qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime) * itemsub_uomratio)
               - (qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime) * itemsub_uomratio)) AS available
   <? else ?>
              (qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime)) AS allocated,
              (qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime)) AS ordered,
-             (sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime)
+             (qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime)
               - qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime)) AS available
   <? endif ?>
 <? elseif exists("byDays") ?>
   <? if exists("normalize") ?>
              (qtyAllocated(sub.itemsite_id, <? value("days") ?>) * itemsub_uomratio) AS allocated,
              (qtyOrdered(sub.itemsite_id, <? value("days") ?>) * itemsub_uomratio) AS ordered,
-             ((sub.itemsite_qtyonhand * itemsub_uomratio) + (qtyOrdered(sub.itemsite_id, <? value("days") ?>) * itemsub_uomratio)
+             ((qtyAvailable(sub.itemsite_id) * itemsub_uomratio) + (qtyOrdered(sub.itemsite_id, <? value("days") ?>) * itemsub_uomratio)
               - (qtyAllocated(sub.itemsite_id, <? value("days") ?>) * itemsub_uomratio)) AS available
   <? else ?>
              (qtyAllocated(sub.itemsite_id, <? value("days") ?>)) AS allocated,
              (qtyOrdered(sub.itemsite_id, <? value("days") ?>)) AS ordered,
-             (sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id, <? value("days") ?>)
+             (qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id, <? value("days") ?>)
               - qtyAllocated(sub.itemsite_id, <? value("days") ?>)) AS available
   <? endif ?>
 <? elseif exists("byDate") ?>
   <? if exists("normalize") ?>
              (qtyAllocated(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE)) * itemsub_uomratio) AS allocated,
              (qtyOrdered(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE)) * itemsub_uomratio) AS ordered,
-             ((sub.itemsite_qtyonhand * itemsub_uomratio) + (qtyOrdered(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE)) * itemsub_uomratio)
+             ((qtyAvailable(sub.itemsite_id) * itemsub_uomratio) + (qtyOrdered(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE)) * itemsub_uomratio)
               - (qtyAllocated(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE)) * itemsub_uomratio)) AS available
   <? else ?>
              (qtyAllocated(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE))) AS allocated,
              (qtyOrdered(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE))) AS ordered,
-             (sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id,
+             (qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id,
              (<? value("date") ?> - CURRENT_DATE)) - qtyAllocated(sub.itemsite_id, (<? value("date") ?> - CURRENT_DATE))) AS available
   <? endif ?>
 <? endif ?>
index 4fc3201..6386fd8 100644 (file)
@@ -29,19 +29,19 @@ SELECT 1 AS dummy,
          cust_number, cohist_cust_id AS cust_number_xtidrole, cust_name,
        <? endif ?>
        <? if exists("byCustomerType") ?>
-         custtype_code, cust_custtype_id AS custtype_code_xtidrole,
+         custtype_code, custtype_id AS custtype_code_xtidrole,
        <? endif ?>
        <? if exists("byItem") ?>
          item_number, item_id AS item_number_xtidrole, itemdescription,
        <? endif ?>
        <? if exists("bySalesRep") ?>
-         salesrep_number, cohist_salesrep_id AS salesrep_number_xtidrole, salesrep_name,
+         salesrep_number, salesrep_id AS salesrep_number_xtidrole, salesrep_name,
        <? endif ?>
        <? if exists("byShippingZone") ?>
          shipzone_name, shipzone_id AS shipzone_name_xtidrole,
        <? endif ?>
        <? if exists("bySite") ?>
-         warehous_code, itemsite_warehous_id AS warehous_code_xtidrole,
+         warehous_code, warehous_id AS warehous_code_xtidrole,
        <? endif ?>
        <? if exists("byCurrency") ?>
          currAbbr,
@@ -76,9 +76,8 @@ SELECT 1 AS dummy,
          'curr' AS totalsales_xtnumericrole,
          0 AS totalunits_xttotalrole,
          0 AS totalsales_xttotalrole
-FROM saleshistory
-WHERE ((COALESCE(cohist_misc_type, '') <> 'F')
- AND  (COALESCE(cohist_misc_type, '') <> 'T')
+FROM saleshistorymisc
+WHERE ( (TRUE)
 <? if exists("startDate") ?>
  AND (cohist_invcdate >= <? value("startDate") ?>)
 <? endif ?>
@@ -96,11 +95,11 @@ WHERE ((COALESCE(cohist_misc_type, '') <> 'F')
 <? endif ?>
 
 <? if exists("warehous_id") ?>
- AND (itemsite_warehous_id=<? value("warehous_id") ?>)
+ AND (warehous_id=<? value("warehous_id") ?>)
 <? endif ?>
 
 <? if exists("item_id") ?>
- AND (itemsite_item_id=<? value("item_id") ?>)
+ AND (item_id=<? value("item_id") ?>)
 <? endif ?>
 
 <? if exists("cust_id") ?>
@@ -112,11 +111,11 @@ WHERE ((COALESCE(cohist_misc_type, '') <> 'F')
 <? endif ?>
 
 <? if exists("salesrep_id") ?>
- AND (cohist_salesrep_id=<? value("salesrep_id") ?>)
+ AND (salesrep_id=<? value("salesrep_id") ?>)
 <? endif ?>
 
 <? if exists("prodcat_id") ?>
- AND (item_prodcat_id=<? value("prodcat_id") ?>)
+ AND (prodcat_id=<? value("prodcat_id") ?>)
 <? endif ?>
 
 <? if exists("prodcat_pattern") ?>
@@ -124,7 +123,7 @@ WHERE ((COALESCE(cohist_misc_type, '') <> 'F')
 <? endif ?>
 
 <? if exists("custtype_id") ?>
- AND (cust_custtype_id=<? value("custtype_id") ?>)
+ AND (custtype_id=<? value("custtype_id") ?>)
 <? endif ?>
 
 <? if exists("custtype_pattern") ?>
@@ -158,7 +157,7 @@ WHERE ((COALESCE(cohist_misc_type, '') <> 'F')
 )
 GROUP BY dummy
 <? if exists("bySalesRep") ?>
- , cohist_salesrep_id, salesrep_number, salesrep_name
+ , salesrep_id, salesrep_number, salesrep_name
 <? endif ?>
 <? if exists("byShippingZone") ?>
  , shipzone_id, shipzone_name, shipzone_descrip
@@ -167,13 +166,13 @@ GROUP BY dummy
  , cohist_cust_id, cust_number, cust_name
 <? endif ?>
 <? if exists("byCustomerType") ?>
- , cust_custtype_id, custtype_code, custtype_descrip
+ , custtype_id, custtype_code, custtype_descrip
 <? endif ?>
 <? if exists("byItem") ?>
  , item_id, item_number, itemdescription
 <? endif ?>
 <? if exists("bySite") ?>
- , itemsite_warehous_id, warehous_code, warehous_descrip
+ , warehous_id, warehous_code, warehous_descrip
 <? endif ?>
 <? if exists("byCurrency") ?>
  , cust_curr_id, currAbbr
index 99f8b82..f49f608 100644 (file)
@@ -8,19 +8,14 @@ SELECT itemsite_id, warehous_code, item_number,
        (item_descrip1 || ' ' || item_descrip2) AS itemdescrip, uom_name,
        itemsite_qtyonhand,
        detailedQOH(itemsite_id, FALSE) AS detailedqoh,
-       itemsite_nnqoh,
-       detailedNNQOH(itemsite_id, FALSE) AS detailednnqoh,
        'qty' AS itemsite_qtyonhand_xtnumericrole,
-       'qty' AS detailedqoh_xtnumericrole,
-       'qty' AS itemsite_nnqoh_xtnumericrole,
-       'qty' AS detailednnqoh_xtnumericrole
+       'qty' AS detailedqoh_xtnumericrole
 FROM whsinfo, item, itemsite, uom
 WHERE ( (itemsite_item_id=item_id)
     AND (item_inv_uom_id=uom_id)
     AND (itemsite_warehous_id=warehous_id)
     AND ((itemsite_loccntrl) OR (itemsite_controlmethod IN ('L', 'S')))
-    AND ((itemsite_qtyonhand <> detailedQOH(itemsite_id, FALSE))
-      OR (itemsite_nnqoh <> detailedNNQOH(itemsite_id, FALSE)))
+    AND (itemsite_qtyonhand <> detailedQOH(itemsite_id, FALSE))
 <? if exists("classcode_id") ?>
     AND (item_classcode_id=<? value("classcode_id") ?>)
 <? elseif exists("classcode_pattern") ?>
index 27e5f04..c0fa648 100644 (file)
@@ -5,6 +5,7 @@
 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
 -- See www.xtuple.com/CPAL for the full text of the software license.
 
+<? if exists("nominal") ?>
 UPDATE ipsiteminfo SET
   ipsitem_price=
 <? if exists("updateByValue") ?>
@@ -21,6 +22,7 @@ FROM selsched, item
 <? endif ?>
 WHERE ( ipsitem_item_id=item_id
   AND selsched_ipshead_id=ipsitem_ipshead_id
+  AND ipsitem_type='N'
 <? if exists("item_id") ?>
   AND item_id=<? value("item_id") ?>
 <? elseif exists("itemgrp_id") ?>
@@ -33,3 +35,68 @@ WHERE ( ipsitem_item_id=item_id
   AND prodcat_code ~ <? value("prodcat_pattern") ?>
 <? endif ?>
 );
+<? endif ?>
+
+<? if exists("discount") ?>
+UPDATE ipsiteminfo SET
+  ipsitem_discntprcnt=
+<? if exists("updateByValue") ?>
+  ipsitem_discntprcnt + (<? value("updateBy") ?> / 100.0)
+<? else ?>
+  roundSale(ipsitem_discntprcnt * (1.0 + (<? value("updateBy") ?> / 100.0)))
+<? endif ?>
+FROM selsched, item
+<? if reExists("itemgrp") ?>
+  JOIN itemgrpitem ON (itemgrpitem_item_id=item_id)
+  JOIN itemgrp ON (itemgrpitem_itemgrp_id=itemgrp_id)
+<? elseif reExists("prodcat") ?>
+  JOIN prodcat ON (prodcat_id=item_prodcat_id)
+<? endif ?>
+WHERE ( ipsitem_item_id=item_id
+  AND selsched_ipshead_id=ipsitem_ipshead_id
+  AND ipsitem_type='D'
+<? if exists("item_id") ?>
+  AND item_id=<? value("item_id") ?>
+<? elseif exists("itemgrp_id") ?>
+  AND itemgrp_id=<? value("itemgrp_id") ?>
+<? elseif exists("itemgrp_pattern") ?>
+  AND itemgrp_name ~ <? value("itemgrp_pattern") ?>
+<? elseif exists("prodcat_id") ?>
+  AND prodcat_id=<? value("prodcat_id") ?>
+<? elseif exists("prodcat_pattern") ?>
+  AND prodcat_code ~ <? value("prodcat_pattern") ?>
+<? endif ?>
+);
+<? endif ?>
+
+<? if exists("markup") ?>
+UPDATE ipsiteminfo SET
+  ipsitem_discntprcnt=
+<? if exists("updateByValue") ?>
+  ipsitem_discntprcnt + (<? value("updateBy") ?> / 100.0)
+<? else ?>
+  roundSale(ipsitem_discntprcnt * (1.0 + (<? value("updateBy") ?> / 100.0)))
+<? endif ?>
+FROM selsched, item
+<? if reExists("itemgrp") ?>
+  JOIN itemgrpitem ON (itemgrpitem_item_id=item_id)
+  JOIN itemgrp ON (itemgrpitem_itemgrp_id=itemgrp_id)
+<? elseif reExists("prodcat") ?>
+  JOIN prodcat ON (prodcat_id=item_prodcat_id)
+<? endif ?>
+WHERE ( ipsitem_item_id=item_id
+  AND selsched_ipshead_id=ipsitem_ipshead_id
+  AND ipsitem_type='M'
+<? if exists("item_id") ?>
+  AND item_id=<? value("item_id") ?>
+<? elseif exists("itemgrp_id") ?>
+  AND itemgrp_id=<? value("itemgrp_id") ?>
+<? elseif exists("itemgrp_pattern") ?>
+  AND itemgrp_name ~ <? value("itemgrp_pattern") ?>
+<? elseif exists("prodcat_id") ?>
+  AND prodcat_id=<? value("prodcat_id") ?>
+<? elseif exists("prodcat_pattern") ?>
+  AND prodcat_code ~ <? value("prodcat_pattern") ?>
+<? endif ?>
+);
+<? endif ?>
index 99fb21c..21c8615 100644 (file)
@@ -2,5 +2,3 @@
 insert into metric (metric_name, metric_value)
 select 'UnifiedBuild', 'true'
 where not exists (select c.metric_id from metric c where c.metric_name = 'UnifiedBuild');
-
-SELECT setMetric('ServerVersion', '4.5.0');
index 3c2b34a..8ffe63e 100644 (file)
@@ -39,8 +39,8 @@
   <name>Subtotal</name>
   <sql>SELECT 
    formatMoney(COALESCE(MAX(selrec.bankrec_endbal) +
---   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date) * -1),0)) AS amount
-   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date)),0)) AS amount
+   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date) * -1),0)) AS amount
+--   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date)),0)) AS amount
  FROM gltrans
    JOIN bankaccnt ON (bankaccnt_accnt_id = gltrans_accnt_id)
    JOIN bankrec selrec ON ((selrec.bankrec_bankaccnt_id = bankaccnt_id)
@@ -55,8 +55,8 @@
   <name>ActualAmount</name>
   <sql>SELECT 
    formatMoney(COALESCE(MAX(selrec.bankrec_endbal) +
---   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date) * -1),0)) AS amount
-   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date)),0)) AS amount
+   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date) * -1),0)) AS amount
+--   SUM(currtolocal(bankaccnt_curr_id,gltrans_amount,gltrans_date)),0)) AS amount
  FROM gltrans
    JOIN bankaccnt ON (bankaccnt_accnt_id = gltrans_accnt_id)
    JOIN bankrec selrec ON ((selrec.bankrec_bankaccnt_id = bankaccnt_id)
     <height>136.499</height>
     <label>
      <rect>
-      <x>454</x>
-      <y>41.4985</y>
+      <x>450</x>
+      <y>43</y>
       <width>162</width>
       <height>15</height>
      </rect>
      </font>
      <right/>
      <vcenter/>
-     <string>Add: Checks in Circulation:</string>
+     <string>Checks in Circulation:</string>
     </label>
     <label>
      <rect>
     </label>
     <label>
      <rect>
-      <x>453</x>
-      <y>73.5</y>
+      <x>450</x>
+      <y>73</y>
       <width>163</width>
       <height>15</height>
      </rect>
      </font>
      <right/>
      <vcenter/>
-     <string>Deduct: Deposits in Circulation:</string>
+     <string>Deposits in Circulation:</string>
     </label>
     <label>
      <rect>
-      <x>396</x>
-      <y>105</y>
+      <x>395</x>
+      <y>103</y>
       <width>219</width>
       <height>15</height>
      </rect>
     </label>
     <label>
      <rect>
-      <x>454</x>
-      <y>25.5</y>
+      <x>450</x>
+      <y>28</y>
       <width>162</width>
       <height>15</height>
      </rect>
     </label>
     <field>
      <rect>
-      <x>642</x>
-      <y>25.4985</y>
+      <x>640</x>
+      <y>28</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <field>
      <rect>
-      <x>642</x>
-      <y>41.5</y>
+      <x>640</x>
+      <y>43</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <label>
      <rect>
-      <x>559</x>
-      <y>57.4985</y>
+      <x>555</x>
+      <y>58</y>
       <width>56</width>
       <height>15</height>
      </rect>
     </label>
     <field>
      <rect>
-      <x>641</x>
-      <y>57.5</y>
+      <x>640</x>
+      <y>58</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <field>
      <rect>
-      <x>642</x>
-      <y>73.5</y>
+      <x>640</x>
+      <y>73</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <field>
      <rect>
-      <x>641</x>
-      <y>89.5</y>
+      <x>640</x>
+      <y>88</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <field>
      <rect>
-      <x>641</x>
-      <y>105</y>
+      <x>640</x>
+      <y>103</y>
       <width>100</width>
       <height>15</height>
      </rect>
     </field>
     <label>
      <rect>
-      <x>439</x>
-      <y>89.499</y>
+      <x>435</x>
+      <y>88</y>
       <width>177</width>
       <height>15</height>
      </rect>
      </font>
      <right/>
      <vcenter/>
-     <string>Add: Adjustments in Circulation:</string>
+     <string>Adjustments in Circulation:</string>
     </label>
    </foot>
   </group>
index b0a2f97..f7bd1f9 100644 (file)
@@ -3,6 +3,12 @@
  <title>Brief Earned Commissions</title>
  <name>BriefEarnedCommissions</name>
  <description></description>
+ <grid>
+  <snap/>
+  <show/>
+  <x>0.05</x>
+  <y>0.05</y>
+ </grid>
  <size>Letter</size>
  <portrait/>
  <topmargin>50</topmargin>
        formatDate(&lt;? value("startDate") ?>) AS startdate,
        formatDate(&lt;? value("endDate") ?>) AS enddate;</sql>
  </querysource>
- <querysource>
+ <querysource loadFromDb="true">
   <name>detail</name>
-  <sql>SELECT cohist_salesrep_id, salesrep_number, salesrep_name, cust_number, cust_name,
-       cohist_ordernumber, cohist_invcnumber, formatDate(cohist_invcdate) AS f_invcdate, currAbbr,
-       formatMoney(SUM(baseextprice)) AS f_extprice,
-       formatMoney(SUM(basecommission)) AS f_commission,
-       SUM(baseextprice) AS extprice,
-       SUM(basecommission) AS commission
-&lt;? if exists("includeMisc") ?>
-FROM saleshistorymisc
-&lt;? else ?>
-FROM saleshistory
-&lt;? endif ?>
-WHERE ( (cohist_commission &lt;> 0)
-  AND (cohist_invcdate BETWEEN &lt;? value("startDate") ?> AND &lt;? value("endDate") ?>)
-
-&lt;? if exists("includeMisc") ?>
-  AND (COALESCE(cohist_misc_type, '') &lt;> 'T')
-  AND (COALESCE(cohist_misc_type, '') &lt;> 'F')
-&lt;? endif ?>
-
-&lt;? if exists("salesrep_id") ?>
-  AND (cohist_salesrep_id=&lt;? value("salesrep_id") ?>)
-&lt;? endif ?>
-)
-GROUP BY cohist_salesrep_id, salesrep_number, salesrep_name, cust_number, cust_name,
-         cohist_ordernumber, cohist_invcnumber, cohist_invcdate, currAbbr
-ORDER BY salesrep_number, cust_number, cohist_invcdate
-</sql>
+  <mqlgroup>briefEarnedCommission</mqlgroup>
+  <mqlname>detail</mqlname>
  </querysource>
  <rpthead>
   <height>221</height>
@@ -527,7 +508,7 @@ ORDER BY salesrep_number, cust_number, cohist_invcdate
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>f_extprice</column>
+     <column>f_sumbaseextprice</column>
     </data>
    </field>
    <field>
@@ -546,7 +527,7 @@ ORDER BY salesrep_number, cust_number, cohist_invcdate
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>f_commission</column>
+     <column>f_sumbasecommission</column>
     </data>
    </field>
    <field>
@@ -772,7 +753,7 @@ ORDER BY salesrep_number, cust_number, cohist_invcdate
    <vcenter/>
    <data>
     <query>detail</query>
-    <column>extprice</column>
+    <column>sumbaseextprice</column>
    </data>
    <format builtin="true">money</format>
    <tracktotal/>
@@ -793,7 +774,7 @@ ORDER BY salesrep_number, cust_number, cohist_invcdate
    <vcenter/>
    <data>
     <query>detail</query>
-    <column>commission</column>
+    <column>sumbasecommission</column>
    </data>
    <format builtin="true">money</format>
    <tracktotal/>
index 31b4dbb..39762d7 100644 (file)
        &lt;? endif ?>
          AS docnumber; </sql>
  </querysource>
- <querysource>
+ <querysource loadFromDb="true">
   <name>detail</name>
-  <sql>SELECT cohist_ordernumber AS sonumber,
-       cohist_invcnumber AS invnumber,
-       formatDate(cohist_orderdate) AS orddate,
-       formatDate(cohist_invcdate, 'Return') AS shipdate,
-       SUM(round(cohist_qtyshipped * currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate),2)) as extended,
-       formatMoney(SUM(round(cohist_qtyshipped * currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate),2))) as f_total,
-       SUM(round(cohist_qtyshipped * currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate),2)) as total
-FROM saleshistory
-  LEFT OUTER JOIN cohead ON (cohead_number=cohist_ordernumber)
-WHERE ((cohist_invcdate BETWEEN &lt;? value("startDate") ?> AND  &lt;? value("endDate") ?>)
-&lt;? if exists("cust_id") ?>
-   AND (cohist_cust_id=&lt;? value("cust_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("shipto_id") ?>
-   AND (cohist_shipto_id=&lt;? value("shipto_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("custtype_id") ?>
-   AND (cust_custtype_id=&lt;? value("custtype_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("custtype_pattern") ?>
-   AND (custtype_code ~ &lt;? value("custtype_pattern") ?>)
-&lt;? endif ?>
-&lt;? if exists("custgrp_id") ?>
-  AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
-                   FROM custgrpitem
-                   WHERE (custgrpitem_custgrp_id=&lt;? value("custgrp_id") ?>)))
-&lt;? endif ?>
-&lt;? if exists("custgrp_pattern") ?>
-  AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
-                   FROM custgrp, custgrpitem
-                   WHERE ( (custgrpitem_custgrp_id=custgrp_id)
-                     AND   (custgrp_name ~ &lt;? value("custgrp_pattern") ?>) )) )
-&lt;? endif ?>
-&lt;? if exists("warehous_id") ?>
-   AND (itemsite_warehous_id=&lt;? value("warehous_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("item_id") ?>
-  AND  (itemsite_item_id=&lt;? value("item_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("prodcat_id") ?>
-   AND (item_prodcat_id=&lt;? value("prodcat_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("prodcat_pattern") ?>
-   AND (item_prodcat_id IN (SELECT prodcat_id
-                            FROM prodcat
-                            WHERE (prodcat_code ~ &lt;? value("prodcat_pattern") ?>)))
-&lt;? endif ?>
-&lt;? if exists("salesrep_id") ?>
-   AND (cohist_salesrep_id=&lt;? value("salesrep_id") ?>)
-&lt;? endif ?>
-      )
-GROUP BY cohead_id, cust_id,cust_number,cust_custtype_id,cohist_cust_id,custtype_code,
-         cust_name,cohist_ordernumber, cohist_ponumber,
-         cohist_invcnumber,cohist_orderdate, cohist_invcdate
-ORDER BY cohist_invcdate, cohist_orderdate;</sql>
+  <mqlgroup>briefSalesHistory</mqlgroup>
+  <mqlname>detail</mqlname>
  </querysource>
  <rpthead>
   <height>221</height>
@@ -185,7 +132,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
    </font>
    <hcenter/>
    <vcenter/>
-   <string>Ship Date</string>
+   <string>Invc. Date</string>
   </label>
   <label>
    <rect>
@@ -396,7 +343,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>sonumber</column>
+     <column>cohist_ordernumber</column>
     </data>
    </field>
    <field>
@@ -415,7 +362,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>invnumber</column>
+     <column>invoicenumber</column>
     </data>
    </field>
    <field>
@@ -434,7 +381,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>f_total</column>
+     <column>f_baseextprice</column>
     </data>
    </field>
    <field>
@@ -453,7 +400,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>shipdate</column>
+     <column>f_invcdate</column>
     </data>
    </field>
    <field>
@@ -472,7 +419,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>orddate</column>
+     <column>f_orderdate</column>
     </data>
    </field>
   </detail>
@@ -584,7 +531,7 @@ ORDER BY cohist_invcdate, cohist_orderdate;</sql>
    <vcenter/>
    <data>
     <query>detail</query>
-    <column>total</column>
+    <column>baseextprice</column>
    </data>
    <format builtin="true">money</format>
    <tracktotal/>
index 0a5453a..14a4c42 100644 (file)
@@ -3,6 +3,12 @@
  <title>Earned Commissions</title>
  <name>EarnedCommissions</name>
  <description></description>
+ <grid>
+  <snap/>
+  <show/>
+  <x>0.05</x>
+  <y>0.05</y>
+ </grid>
  <size>Letter</size>
  <portrait/>
  <topmargin>50</topmargin>
@@ -22,7 +28,7 @@
        formatDate(&lt;? value("startDate") ?>) AS startdate,
        formatDate(&lt;? value("endDate") ?>) AS enddate;</sql>
  </querysource>
- <querysource loadFromDb="true" >
+ <querysource loadFromDb="true">
   <name>detail</name>
   <mqlgroup>salesHistory</mqlgroup>
   <mqlname>detail</mqlname>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>item_number</column>
+     <column>itemnumber</column>
     </data>
    </field>
    <field>
     <query>detail</query>
     <column>baseextprice</column>
    </data>
-   <tracktotal builtin="true" >qty</tracktotal>
+   <format builtin="true">qty</format>
+   <tracktotal/>
   </field>
   <field>
    <rect>
     <query>detail</query>
     <column>basecommission</column>
    </data>
-   <tracktotal builtin="true" >qty</tracktotal>
+   <format builtin="true">qty</format>
+   <tracktotal/>
   </field>
  </rptfoot>
 </report>
index 12b5c42..0fdcad7 100644 (file)
@@ -51,7 +51,7 @@
              END AS altId,
              item_number, item_descrip1, item_descrip2, item_inv_uom_id,
              warehous_id, warehous_code, itemsite_leadtime,
-             itemsite_qtyonhand AS qtyonhand,
+             qtyAvailable(itemsite_id) AS qtyonhand,
              CASE WHEN itemsite_useparams THEN itemsite_reorderlevel
                   ELSE 0.0
              END AS reorderlevel,
index d0c25b4..9be2630 100644 (file)
@@ -73,7 +73,7 @@
                      cohead_id, cohead_number, cust_number, cust_name,
                      item_number, (item_descrip1 || ' ' || item_descrip2) AS item_description,
                      uom_name, item_picklist,
-                     noNeg(itemsite_qtyonhand) AS qoh,
+                     noNeg(qtyAvailable(itemsite_id)) AS qoh,
                      noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) AS sobalance,
                      qtyAllocated(itemsite_id, coitem_scheddate) AS allocated,
                      qtyOrdered(itemsite_id, coitem_scheddate) AS ordered,
@@ -95,7 +95,7 @@
                   AND (wo_status IN ('E','R','I'))
                   AND (wo_qtyord-wo_qtyrcv > 0)
                   AND (noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned-qtyatshipping(coitem_id)) > 
-                        (SELECT itemsite_qtyonhand FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
+                        (SELECT qtyAvailable(itemsite_id) AS availableqoh FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
 &lt;? endif ?>
                 WHERE((coitem_cohead_id=cohead_id)
                   AND (cohead_cust_id=cust_id)
index 794fc0a..251dcf4 100644 (file)
@@ -62,7 +62,7 @@
                  FROM ( SELECT itemsite_id, coitem_id,
                                item_number, (item_descrip1 || ' ' || item_descrip2) AS item_description,
                                uom_name, item_picklist,
-                               noNeg(itemsite_qtyonhand) AS qoh,
+                               noNeg(qtyAvailable(itemsite_id)) AS qoh,
                                noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned) AS sobalance,
                                qtyAllocated(itemsite_id, coitem_scheddate) AS allocated,
                                qtyOrdered(itemsite_id, coitem_scheddate) AS ordered,
@@ -83,7 +83,7 @@
                               AND (wo_status IN ('E','R','I'))
                               AND (wo_qtyord-wo_qtyrcv > 0)
                               AND (noNeg(coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned-qtyatshipping(coitem_id)) > 
-                               (SELECT itemsite_qtyonhand FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
+                               (SELECT qtyAvailable(itemsite_id) AS availableqoh FROM itemsite WHERE (itemsite_id=coitem_itemsite_id))))
                  &lt;? endif ?>
                         WHERE ( (coitem_cohead_id=cohead_id)
                          AND (coitem_itemsite_id=itemsite_id)
index 4d2e2d6..c4571a9 100644 (file)
@@ -55,7 +55,7 @@
              END AS altId,
              item_number, item_descrip1, item_descrip2, item_inv_uom_id,
              warehous_id, warehous_code, itemsite_leadtime,
-             itemsite_qtyonhand AS qtyonhand,
+             qtyAvailable(itemsite_id) AS qtyonhand,
              CASE WHEN itemsite_useparams THEN itemsite_reorderlevel
                   ELSE 0.0
              END AS reorderlevel,
index ba3438e..e5eace8 100644 (file)
@@ -3,6 +3,12 @@
  <title>Item Costs By Class Code</title>
  <name>ItemCostsByClassCode</name>
  <description></description>
+ <grid>
+  <snap/>
+  <show/>
+  <x>0.05</x>
+  <y>0.05</y>
+ </grid>
  <size>Letter</size>
  <portrait/>
  <topmargin>50</topmargin>
@@ -43,6 +49,9 @@
            FROM item, classcode, uom
           WHERE ((item_classcode_id=classcode_id)
             AND (item_inv_uom_id=uom_id)
+          &lt;? if exists("onlyShowActive") ?>
+            AND (item_active) 
+          &lt;? endif ?> 
           &lt;? if exists("classcode_id") ?>
             AND (classcode_id=&lt;? value("classcode_id") ?>)
           &lt;? elseif exists("classcode_pattern") ?>
index 48fb294..c547834 100644 (file)
@@ -136,7 +136,7 @@ SELECT shiphead_number, 'T/O #:' AS ordertype,
                                              AND  (invcitem_warehous_id=itemsite_warehous_id)
                                              AND  (invcitem_linenumber=coitem_linenumber)
                                              AND  (cohead_id=coitem_cohead_id))) > 0)) THEN 'P'
-            WHEN (coitem_status='O' AND (itemsite_qtyonhand - qtyAllocated(itemsite_id, CURRENT_DATE)
+            WHEN (coitem_status='O' AND (qtyAvailable(itemsite_id) - qtyAllocated(itemsite_id, CURRENT_DATE)
                                          + qtyOrdered(itemsite_id, CURRENT_DATE))
                                           >= (coitem_qtyord - coitem_qtyshipped + coitem_qtyreturned)) THEN 'R'
             ELSE coitem_status
index e310daf..5d0a545 100644 (file)
@@ -41,7 +41,7 @@
   <sql>SELECT warehous_code, item_number, item_descrip1, item_descrip2,
        formatDate(reorderdate) AS f_reorderdate,
        formatQty(reorderlevel) AS f_reorderlevel,
-       formatQty((itemsite_qtyonhand - qtyAllocated(itemsite_id, reorderdate) + qtyOrdered(itemsite_id, reorderdate))) AS f_projavail,
+       formatQty((qtyNetable(itemsite_id) - qtyAllocated(itemsite_id, reorderdate) + qtyOrdered(itemsite_id, reorderdate))) AS f_projavail,
        reorderdate 
   FROM ( SELECT itemsite_id,
                 CASE WHEN (item_type IN ('M', 'B', 'T')) THEN 1
                      ELSE 3
                 END AS itemtype,
                 warehous_code, item_number, item_descrip1, item_descrip2,
-                reorderDate(itemsite_id, &lt;? value(&quot;lookAheadDays&quot;) ?>, &lt;? if exists(&quot;includePlannedOrder&quot;) ?>true&lt;? else ?>false&lt;? endif ?>) AS reorderdate, itemsite_qtyonhand,
+                reorderDate(itemsite_id, &lt;? value(&quot;lookAheadDays&quot;) ?>, &lt;? if exists(&quot;includePlannedOrder&quot;) ?>true&lt;? else ?>false&lt;? endif ?>) AS reorderdate,
                 reorderlevel 
            FROM ( SELECT itemsite_id, itemsite_item_id, itemsite_warehous_id,
-                         itemsite_qtyonhand,
                          CASE WHEN(itemsite_useparams) THEN itemsite_reorderlevel ELSE 0.0 END AS reorderlevel
                     FROM itemsite 
                    WHERE ((true)
index 04dd1b2..cd649f0 100644 (file)
@@ -41,7 +41,7 @@
  <querysource>
   <name>info</name>
   <sql>SELECT
-       formatQty(itemsite_qtyonhand) AS qoh,
+       formatQty(qtyAvailable(itemsite_id)) AS qoh,
        formatQty(CASE WHEN(itemsite_useparams) THEN itemsite_reorderlevel ELSE 0.0 END) AS reorderlevel,
        formatQty(CASE WHEN(itemsite_useparams) THEN itemsite_ordertoqty ELSE 0.0 END) AS ordertoqty,
        formatQty(CASE WHEN(itemsite_useparams) THEN itemsite_multordqty ELSE 0.0 END) AS multorderqty 
index e21848e..5a54703 100644 (file)
  <bottommargin>50</bottommargin>
  <rightmargin>50</rightmargin>
  <leftmargin>50</leftmargin>
- <querysource>
+ <querysource loadFromDb="true">
   <name>detail</name>
-  <sql>SELECT cohist_ordernumber AS sonumber,
-       cohist_invcnumber AS invnumber,
-       formatDate(cohist_orderdate) AS orddate,
-       formatDate(cohist_invcdate, 'Return') AS invcdate,
-       item_number, item_descrip1, item_descrip2,
-       formatQty(cohist_qtyshipped) AS shipped,
-       &lt;? if exists("showPrices") ?>
-       formatPrice(currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate)) AS unitprice,
-       formatMoney(round(cohist_qtyshipped * currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate),2)) AS f_total,
-       &lt;? else ?>
-       '' AS unitprice,
-       '' AS f_total,
-       &lt;? endif ?>
-       round(cohist_qtyshipped * currtobase(cohist_curr_id,cohist_unitprice,cohist_invcdate),2) AS total
-  FROM cohist JOIN custinfo ON (cust_id=cohist_cust_id)
-              JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
-&lt;? if exists("includeMisc") ?>
-              LEFT OUTER JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
-              LEFT OUTER JOIN site() ON (warehous_id=itemsite_warehous_id)
-              LEFT OUTER JOIN item ON (item_id=itemsite_item_id)
-&lt;? else ?>
-              JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
-              JOIN site() ON (warehous_id=itemsite_warehous_id)
-              JOIN item ON (item_id=itemsite_item_id)
-&lt;? endif ?>
-&lt;? if exists("cohead_id") ?>
-              JOIN cohead ON (cohead_number=cohist_ordernumber)
-&lt;? endif ?>
-WHERE ( (true)
-&lt;? if exists("includeMisc") ?>
-  AND  (COALESCE(cohist_misc_type, '') &lt;> 'F')
-  AND  (COALESCE(cohist_misc_type, '') &lt;> 'T')
-&lt;? endif ?>
-&lt;? if exists("startDate") ?>
-  AND  (cohist_invcdate >= &lt;? value("startDate") ?>)
-&lt;? endif ?>
-&lt;? if exists("endDate") ?>
-  AND  (cohist_invcdate &lt;= &lt;? value("endDate") ?>)
-&lt;? endif ?>
-&lt;? if exists("shipStartDate") ?>
-  AND  (cohist_shipdate >= &lt;? value("shipStartDate") ?>)
-&lt;? endif ?>
-&lt;? if exists("shipEndDate") ?>
-  AND  (cohist_shipdate &lt;= &lt;? value("shipEndDate") ?>)
-&lt;? endif ?>
-&lt;? if exists("salesrep_id") ?>
-  AND  (cohist_salesrep_id=&lt;? value("salesrep_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("shipto_id") ?>
-  AND  (cohist_shipto_id=&lt;? value("shipto_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("billToName") ?>
-  AND  (UPPER(cohist_billtoname) ~ UPPER(&lt;? value("billToName") ?>))
-&lt;? endif ?>
-&lt;? if exists("cust_id") ?>
-  AND  (cohist_cust_id=&lt;? value("cust_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("custtype_id") ?>
-  AND  (cust_custtype_id=&lt;? value("custtype_id") ?>)
-&lt;? elseif exists("custtype_pattern") ?>
-  AND  (cust_custtype_id IN (SELECT DISTINCT custtype_id
-                             FROM custtype
-                             WHERE (custtype_code ~ &lt;? value("custtype_pattern") ?>)))
-&lt;? endif ?>
-&lt;? if exists("by_custgrp" ?>
-  AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
-                   FROM custgrpitem))
-&lt;? endif ?>
-&lt;? if exists("custgrp_id") ?>
-  AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
-                   FROM custgrpitem
-                   WHERE (custgrpitem_custgrp_id=&lt;? value("custgrp_id") ?>)))
-&lt;? endif ?>
-&lt;? if exists("custgrp_pattern") ?>
-  AND (cust_id IN (SELECT DISTINCT custgrpitem_cust_id
-                   FROM custgrp, custgrpitem
-                   WHERE ( (custgrpitem_custgrp_id=custgrp_id)
-                     AND   (custgrp_name ~ &lt;? value("custgrp_pattern") ?>) )) )
-&lt;? endif ?>
-
-&lt;? if exists("item_id") ?>
-  AND  (itemsite_item_id=&lt;? value("item_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("prodcat_id") ?>
-  AND (item_prodcat_id=&lt;? value("prodcat_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("prodcat_pattern") ?>
-  AND (item_prodcat_id IN (SELECT DISTINCT prodcat_id
-                           FROM prodcat
-                           WHERE (prodcat_code ~ &lt;? value("prodcat_pattern") ?>)))
-&lt;? endif ?>
-
-&lt;? if exists("warehous_id") ?>
-  AND  (itemsite_warehous_id=&lt;? value("warehous_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("shipzone_id") ?>
-  AND (cohist_shipzone_id=&lt;? value("shipzone_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("saletype_id") ?>
-  AND (cohist_saletype_id=&lt;? value("saletype_id") ?>)
-&lt;? endif ?>
-&lt;? if exists("cohead_id") ?>
-  AND (cohead_id=&lt;? value("cohead_id") ?>)
-&lt;? endif ?>
-      )
-ORDER BY cohist_invcdate, item_number</sql>
+  <mqlgroup>salesHistory</mqlgroup>
+  <mqlname>detail</mqlname>
  </querysource>
  <querysource>
   <name>head</name>
@@ -496,6 +392,50 @@ ORDER BY cohist_invcdate, item_number</sql>
  </pghead>
  <section>
   <name>detail</name>
+  <group>
+   <name>total</name>
+   <column></column>
+   <foot>
+    <height>39</height>
+    <field>
+     <rect>
+      <x>660</x>
+      <y>9</y>
+      <width>80</width>
+      <height>15</height>
+     </rect>
+     <font>
+      <face>Arial</face>
+      <size>8</size>
+      <weight>bold</weight>
+     </font>
+     <right/>
+     <vcenter/>
+     <data>
+      <query>detail</query>
+      <column>baseextprice</column>
+     </data>
+     <format builtin="true">money</format>
+     <tracktotal/>
+    </field>
+    <label>
+     <rect>
+      <x>570</x>
+      <y>9</y>
+      <width>80</width>
+      <height>15</height>
+     </rect>
+     <font>
+      <face>Arial</face>
+      <size>8</size>
+      <weight>normal</weight>
+     </font>
+     <right/>
+     <vcenter/>
+     <string>Total Sales:</string>
+    </label>
+   </foot>
+  </group>
   <detail>
    <key>
     <query>detail</query>
@@ -536,7 +476,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>sonumber</column>
+     <column>cohist_ordernumber</column>
     </data>
    </field>
    <field>
@@ -574,7 +514,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>unitprice</column>
+     <column>f_baseunitprice</column>
     </data>
    </field>
    <field>
@@ -593,7 +533,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>orddate</column>
+     <column>f_orderdate</column>
     </data>
    </field>
    <field>
@@ -612,7 +552,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>shipped</column>
+     <column>f_qtyshipped</column>
     </data>
    </field>
    <line>
@@ -638,7 +578,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>invcdate</column>
+     <column>f_invcdate</column>
     </data>
    </field>
    <field>
@@ -657,7 +597,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>item_number</column>
+     <column>itemnumber</column>
     </data>
    </field>
    <field>
@@ -676,7 +616,7 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>f_total</column>
+     <column>f_baseextprice</column>
     </data>
    </field>
    <field>
@@ -695,57 +635,11 @@ ORDER BY cohist_invcdate, item_number</sql>
     <vcenter/>
     <data>
      <query>detail</query>
-     <column>invnumber</column>
+     <column>invoicenumber</column>
     </data>
    </field>
   </detail>
  </section>
- <section>
-  <name>total</name>
-  <detail>
-   <key>
-    <query>showPrices</query>
-   </key>
-   <height>16</height>
-   <field>
-    <rect>
-     <x>665</x>
-     <y>0</y>
-     <width>80</width>
-     <height>15</height>
-    </rect>
-    <font>
-     <face>Arial</face>
-     <size>8</size>
-     <weight>bold</weight>
-    </font>
-    <right/>
-    <vcenter/>
-    <data>
-     <query>detail</query>
-     <column>total</column>
-    </data>
-    <format builtin="true">money</format>
-    <tracktotal/>
-   </field>
-   <label>
-    <rect>
-     <x>575</x>
-     <y>0</y>
-     <width>80</width>
-     <height>15</height>
-    </rect>
-    <font>
-     <face>Arial</face>
-     <size>8</size>
-     <weight>normal</weight>
-    </font>
-    <right/>
-    <vcenter/>
-    <string>Total Sales:</string>
-   </label>
-  </detail>
- </section>
  <pgfoot>
   <height>16</height>
   <label>
index 0a9d355..4a5c328 100644 (file)
        item_number,
        item_descrip1,
        item_descrip2,
-       formatQty(sub.itemsite_qtyonhand) AS f_qtyonhand,
+       formatQty(qtyAvailable(sub.itemsite_id)) AS f_qtyonhand,
        formatQty(CASE WHEN(sub.itemsite_useparams) THEN sub.itemsite_reorderlevel ELSE 0.0 END) AS f_reorderlevel,
        sub.itemsite_leadtime as leadtime,
 &lt;? if exists(&quot;byDays&quot;) ?>
        formatQty(qtyAllocated(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>)) AS f_allocated,
        formatQty(qtyOrdered(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>)) AS f_ordered,
-       formatQty(sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>) - qtyAllocated(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>)) as f_avail
+       formatQty(qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>) - qtyAllocated(sub.itemsite_id, &lt;? value(&quot;byDays&quot;) ?>)) as f_avail
 &lt;? elseif exists(&quot;byDate&quot;) ?>
        formatQty(qtyAllocated(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE))) AS f_allocated,
        formatQty(qtyOrdered(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE))) AS f_ordered,
-       formatQty(sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE)) - qtyAllocated(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE))) as f_avail
+       formatQty(qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE)) - qtyAllocated(sub.itemsite_id, (&lt;? value(&quot;byDate&quot;) ?> - CURRENT_DATE))) as f_avail
 &lt;? else ?>
        formatQty(qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime)) AS f_allocated,
        formatQty(qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime)) AS f_ordered,
-       formatQty(sub.itemsite_qtyonhand + qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime) - qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime)) as f_avail
+       formatQty(qtyAvailable(sub.itemsite_id) + qtyOrdered(sub.itemsite_id, sub.itemsite_leadtime) - qtyAllocated(sub.itemsite_id, sub.itemsite_leadtime)) as f_avail
 &lt;? endif ?>
   FROM item, itemsite AS sub, itemsite AS root, whsinfo, itemsub
  WHERE ((sub.itemsite_item_id=item_id)
diff --git a/foundation-database/public/tables/setVersion.sql b/foundation-database/public/tables/setVersion.sql
new file mode 100644 (file)
index 0000000..bf8d03a
--- /dev/null
@@ -0,0 +1 @@
+SELECT setMetric('ServerVersion', '4.7.0Beta');
index 6c78eb8..f920ca7 100644 (file)
@@ -523,12 +523,14 @@ BEGIN
   IF (TG_OP = 'INSERT') THEN
     -- Create Purchase Request if flagged to do so
     IF ((NEW.coitem_order_type='R') AND (NEW.coitem_order_id=-1)) THEN
-      SELECT createpr(CAST(cohead_number AS INTEGER), 'S', NEW.coitem_id) INTO _orderid
+      SELECT createPR(CAST(cohead_number AS INTEGER), 'S', NEW.coitem_id) INTO _orderid
       FROM cohead
       WHERE (cohead_id=NEW.coitem_cohead_id);
       IF (_orderid > 0) THEN
         UPDATE coitem SET coitem_order_id=_orderid
         WHERE (coitem_id=NEW.coitem_id);
+      ELSE
+        RAISE EXCEPTION 'CreatePR failed, result=%', _orderid;
       END IF;
     END IF;
 
@@ -550,6 +552,8 @@ BEGIN
         IF (_orderid > 0) THEN
           UPDATE coitem SET coitem_order_id=_orderid
           WHERE (coitem_id=NEW.coitem_id);
+        ELSE
+          RAISE EXCEPTION 'CreatePurchaseToSale failed, result=%', _orderid;
         END IF;
       END IF;
     END IF;
index 6a726da..e8f6d14 100644 (file)
@@ -8,7 +8,8 @@ DECLARE
 BEGIN
 
   -- Cache some information
-  SELECT item_type INTO _r
+  -- Added item_number as part of feature request 21645
+  SELECT item_type, item_number INTO _r
   FROM item
   WHERE (item_id=NEW.itemsite_item_id);
  
@@ -44,11 +45,11 @@ BEGIN
     END IF;
   END IF;
 
+-- Added item_number to error messages displayed to fulfill Feature Request 21645
   IF (NEW.itemsite_qtyonhand < 0 AND NEW.itemsite_costmethod = 'A') THEN
-    RAISE EXCEPTION 'Itemsite (%) is set to use average costing and is not allowed to have a negative quantity on hand.', NEW.itemsite_id;
+    RAISE EXCEPTION 'Itemsite (%) is set to use average costing and is not allowed to have a negative quantity on hand.', 'ID: ' || NEW.itemsite_id || ', Item: ' || _r.item_number;
   ELSIF (NEW.itemsite_value < 0 AND NEW.itemsite_costmethod = 'A') THEN
-    RAISE EXCEPTION 'This transaction results in a negative itemsite value.  Itemsite (%) is set to use average costing and is not allowed to have a negative value.', NEW.itemsite_id;
-  END IF;
+    RAISE EXCEPTION 'This transaction results in a negative itemsite value.  Itemsite (%) is set to use average costing and is not allowed to have a negative value.', 'ID: ' || NEW.itemsite_id || ', Item: ' || _r.item_number;  END IF;
 
 --  Handle the ChangeLog
   IF ( SELECT (metric_value='t')
@@ -364,19 +365,6 @@ BEGIN
 
         RAISE NOTICE 'Deleting item site detail records,';
 
-        SELECT SUM(itemloc_qty) INTO _qty
-        FROM itemloc, location
-        WHERE ((itemloc_location_id=location_id)
-        AND (NOT location_netable) 
-        AND (itemloc_itemsite_id=OLD.itemsite_id));
-
-        IF (_qty != 0) THEN
-          UPDATE itemsite
-          SET itemsite_qtyonhand = itemsite_qtyonhand + _qty,
-            itemsite_nnqoh = itemsite_nnqoh - _qty
-          WHERE (itemsite_id=OLD.itemsite_id);
-        END IF;
-
         DELETE FROM itemloc
         WHERE (itemloc_itemsite_id=OLD.itemsite_id);
       END IF;
index 9c78831..c82a0f6 100644 (file)
@@ -82,23 +82,6 @@ DECLARE
 
 BEGIN
 
-  -- Maintain itemsite_qtyonhand and itemsite_nnqoh when location_netable changes
-  IF (TG_OP = 'UPDATE') THEN
-    IF (OLD.location_netable <> NEW.location_netable) THEN
-      FOR _itemloc IN SELECT * FROM itemloc WHERE (itemloc_location_id=NEW.location_id) LOOP
-        IF (NEW.location_netable) THEN
-          UPDATE itemsite SET itemsite_qtyonhand = itemsite_qtyonhand + _itemloc.itemloc_qty,
-                              itemsite_nnqoh = itemsite_nnqoh - _itemloc.itemloc_qty
-          WHERE (itemsite_id=_itemloc.itemloc_itemsite_id);
-        ELSE
-          UPDATE itemsite SET itemsite_qtyonhand = itemsite_qtyonhand - _itemloc.itemloc_qty,
-                              itemsite_nnqoh = itemsite_nnqoh + _itemloc.itemloc_qty
-          WHERE (itemsite_id=_itemloc.itemloc_itemsite_id);
-        END IF;
-      END LOOP;
-    END IF;
-  END IF;
-  
   RETURN NEW;
 
 END;
index e873cc8..3e0d663 100644 (file)
@@ -364,6 +364,37 @@ CREATE VIEW docinfo AS
         WHERE ((docass_source_type='S')
          AND (docass_source_id=cohead_id)
          AND (cust_id=cohead_cust_id))
+------------ INVOICE -----------
+ UNION ALL
+ SELECT docass_id AS id,
+        invchead_invcnumber AS target_number,
+        docass_target_type AS target_type,
+        docass_target_id AS target_id,
+        docass_source_type AS source_type,
+        docass_source_id AS source_id,
+        cust_name AS name, firstline(invchead_notes) AS description,
+        docass_purpose AS purpose
+        FROM docass, invchead, custinfo
+        WHERE ((docass_target_type='INV')
+         AND (docass_target_id=invchead_id)
+         AND (cust_id=invchead_cust_id))
+ UNION ALL
+ SELECT docass_id AS id,
+        invchead_invcnumber AS target_number,
+        docass_source_type AS target_type,
+        docass_source_id AS target_id,
+        docass_target_type AS source_type,
+        docass_target_id AS source_id,
+        cust_name AS name, firstline(invchead_notes) AS description,
+        CASE 
+          WHEN docass_purpose = 'A' THEN 'C'
+          WHEN docass_purpose = 'C' THEN 'A'
+          ELSE docass_purpose
+        END AS purpose
+        FROM docass, invchead, custinfo
+        WHERE ((docass_source_type='INV')
+         AND (docass_source_id=invchead_id)
+         AND (cust_id=invchead_cust_id))
  ------------ PURCHASE ORDER -----------
  UNION ALL
  SELECT docass_id AS id,
index 7db4ed2..d5471f9 100644 (file)
@@ -1,23 +1,17 @@
 SELECT dropIfExists('view', 'saleshistory');
 CREATE VIEW saleshistory AS
-SELECT cohist.*,
-       CASE WHEN (cohist_invcnumber='-1') THEN 'Credit'
-            ELSE cohist_invcnumber
-       END AS invoicenumber,
-       cust_id, cust_number, cust_name, cust_curr_id, cust_custtype_id, custtype_code, custtype_descrip,
-       salesrep_number, salesrep_name, shipzone_id, shipzone_name, shipzone_descrip,
-       itemsite_warehous_id, itemsite_item_id,
-       item_id, item_number, item_descrip1, (item_descrip1 || ' ' || item_descrip2) AS itemdescription,
-       item_prodcat_id, warehous_code, warehous_descrip, prodcat_code,
-       currtobase(cohist_curr_id, cohist_commission, cohist_invcdate) AS basecommission,
-       currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate) AS baseunitprice,
-       currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate) AS custunitprice,
+SELECT *,
        round((cohist_qtyshipped * cohist_unitprice), 2) AS extprice,
-       round((cohist_qtyshipped * currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate)), 2) AS baseextprice,
-       round((cohist_qtyshipped * currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate)), 2) AS custextprice,
+       round((cohist_qtyshipped * baseunitprice), 2) AS baseextprice,
+       round((cohist_qtyshipped * custunitprice), 2) AS custextprice,
        round((cohist_qtyshipped * cohist_unitcost), 4) AS extcost,
+       round((cohist_qtyshipped * baseunitprice) - (cohist_qtyshipped * cohist_unitcost), 2) AS margin,
+       CASE WHEN (cohist_qtyshipped * baseunitprice > 0.0) THEN
+            (round((cohist_qtyshipped * baseunitprice) - (cohist_qtyshipped * cohist_unitcost), 2) /
+             round((cohist_qtyshipped * baseunitprice), 2))
+            ELSE 0.0
+       END AS marginpercent,
        currConcat(cohist_curr_id) AS currAbbr,
-       'Return'::TEXT AS cohist_invcdate_xtnullrole,
        'qty'::TEXT AS cohist_qtyshipped_xtnumericrole,
        'salesprice'::TEXT AS cohist_unitprice_xtnumericrole,
        'salesprice'::TEXT AS baseunitprice_xtnumericrole,
@@ -27,22 +21,39 @@ SELECT cohist.*,
        'curr'::TEXT AS baseextprice_xtnumericrole,
        'cost'::TEXT AS cohist_unitcost_xtnumericrole,
        'curr'::TEXT AS extcost_xtnumericrole,
+       'curr'::TEXT AS margin_xtnumericrole,
+       'percent'::TEXT AS marginpercent_xtnumericrole,
        'curr'::TEXT AS cohist_commission_xtnumericrole,
-       'curr'::TEXT AS basecommission_xtnumericrole,
-       0 AS cohist_qtyshipped_xttotalrole,
-       0 AS custextprice_xttotalrole,
-       0 AS baseextprice_xttotalrole,
-       0 AS extcost_xttotalrole,
-       0 AS basecommission_xttotalrole
+       'curr'::TEXT AS basecommission_xtnumericrole
+FROM (
+SELECT cohist.*,
+       COALESCE(cohead_id,-1) AS cohead_id,
+       cust_id, cust_number, cust_name, cust_curr_id,
+       custtype_id, custtype_code, custtype_descrip,
+       salesrep_id, salesrep_number, salesrep_name,
+       shipzone_id, shipzone_name, shipzone_descrip,
+       saletype_code, saletype_descr,
+       itemsite_id,
+       warehous_id, warehous_code, warehous_descrip,
+       item_id, item_number, item_descrip1, item_descrip2,
+       (item_descrip1 || ' ' || item_descrip2) AS itemdescription,
+       COALESCE(item_number, cohist_misc_descrip) AS itemnumber,
+       prodcat_id, prodcat_code,
+       currtobase(cohist_curr_id, cohist_commission, cohist_invcdate) AS basecommission,
+       currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate) AS baseunitprice,
+       currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate) AS custunitprice
 FROM cohist JOIN custinfo ON (cust_id=cohist_cust_id)
-            JOIN custtype ON (custtype_id=cust_custtype_id)
-            JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
+            LEFT OUTER JOIN cohead ON (cohead_number=cohist_ordernumber)
+            LEFT OUTER JOIN custtype ON (custtype_id=cust_custtype_id)
+            LEFT OUTER JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
+            LEFT OUTER JOIN shiptoinfo ON (shipto_id=cohist_shipto_id)
+            LEFT OUTER JOIN shipzone ON (shipzone_id=shipto_shipzone_id)
+            LEFT OUTER JOIN saletype ON (saletype_id=cohist_saletype_id)
             JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
             JOIN site() ON (warehous_id=itemsite_warehous_id)
             JOIN item ON (item_id=itemsite_item_id)
             JOIN prodcat ON (prodcat_id=item_prodcat_id)
-            LEFT OUTER JOIN shiptoinfo ON (shipto_id=cohist_shipto_id)
-            LEFT OUTER JOIN shipzone ON (shipzone_id=shipto_shipzone_id);
+     ) AS data;
 
 REVOKE ALL ON TABLE saleshistory FROM PUBLIC;
 GRANT  ALL ON TABLE saleshistory TO GROUP xtrole;
index 9fd0236..b1c467f 100644 (file)
@@ -1,23 +1,17 @@
 SELECT dropIfExists('view', 'saleshistorymisc');
 CREATE VIEW saleshistorymisc AS
-SELECT cohist.*,
-       CASE WHEN (cohist_invcnumber='-1') THEN 'Credit'
-            ELSE cohist_invcnumber
-       END AS invoicenumber,
-       cust_id, cust_number, cust_name, cust_curr_id, cust_custtype_id, custtype_code,
-       salesrep_number, salesrep_name, shipzone_id, shipzone_name,
-       itemsite_warehous_id, itemsite_item_id,
-       item_number, item_descrip1, (item_descrip1 || ' ' || item_descrip2) AS itemdescription,
-       item_prodcat_id, warehous_code, prodcat_code,
-       currtobase(cohist_curr_id, cohist_commission, cohist_invcdate) AS basecommission,
-       currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate) AS baseunitprice,
-       currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate) AS custunitprice,
+SELECT *,
        round((cohist_qtyshipped * cohist_unitprice), 2) AS extprice,
-       round((cohist_qtyshipped * currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate)), 2) AS baseextprice,
-       round((cohist_qtyshipped * currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate)), 2) AS custextprice,
+       round((cohist_qtyshipped * baseunitprice), 2) AS baseextprice,
+       round((cohist_qtyshipped * custunitprice), 2) AS custextprice,
        round((cohist_qtyshipped * cohist_unitcost), 4) AS extcost,
+       round((cohist_qtyshipped * baseunitprice) - (cohist_qtyshipped * cohist_unitcost), 2) AS margin,
+       CASE WHEN (cohist_qtyshipped * baseunitprice > 0.0) THEN
+            (round((cohist_qtyshipped * baseunitprice) - (cohist_qtyshipped * cohist_unitcost), 2) /
+             round((cohist_qtyshipped * baseunitprice), 2))
+            ELSE 0.0
+       END AS marginpercent,
        currConcat(cohist_curr_id) AS currAbbr,
-       'Return'::TEXT AS cohist_invcdate_xtnullrole,
        'qty'::TEXT AS cohist_qtyshipped_xtnumericrole,
        'salesprice'::TEXT AS cohist_unitprice_xtnumericrole,
        'salesprice'::TEXT AS baseunitprice_xtnumericrole,
@@ -27,22 +21,41 @@ SELECT cohist.*,
        'curr'::TEXT AS baseextprice_xtnumericrole,
        'cost'::TEXT AS cohist_unitcost_xtnumericrole,
        'curr'::TEXT AS extcost_xtnumericrole,
+       'curr'::TEXT AS margin_xtnumericrole,
+       'percent'::TEXT AS marginpercent_xtnumericrole,
        'curr'::TEXT AS cohist_commission_xtnumericrole,
-       'curr'::TEXT AS basecommission_xtnumericrole,
-       0 AS cohist_qtyshipped_xttotalrole,
-       0 AS custextprice_xttotalrole,
-       0 AS baseextprice_xttotalrole,
-       0 AS extcost_xttotalrole,
-       0 AS basecommission_xttotalrole
+       'curr'::TEXT AS basecommission_xtnumericrole
+FROM (
+SELECT cohist.*,
+       COALESCE(cohead_id,-1) AS cohead_id,
+       cust_id, cust_number, cust_name, cust_curr_id,
+       custtype_id, custtype_code, custtype_descrip,
+       salesrep_id, salesrep_number, salesrep_name,
+       shipzone_id, shipzone_name, shipzone_descrip,
+       saletype_code, saletype_descr,
+       itemsite_id,
+       warehous_id, warehous_code, warehous_descrip,
+       item_id, item_number, item_descrip1, item_descrip2,
+       (item_descrip1 || ' ' || item_descrip2) AS itemdescription,
+       COALESCE(item_number, cohist_misc_descrip) AS itemnumber,
+       prodcat_id, prodcat_code,
+       currtobase(cohist_curr_id, cohist_commission, cohist_invcdate) AS basecommission,
+       currtobase(cohist_curr_id, cohist_unitprice, cohist_invcdate) AS baseunitprice,
+       currtocurr(cohist_curr_id, cust_curr_id, cohist_unitprice, cohist_invcdate) AS custunitprice
 FROM cohist JOIN custinfo ON (cust_id=cohist_cust_id)
-            JOIN custtype ON (custtype_id=cust_custtype_id)
-            JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
+            LEFT OUTER JOIN cohead ON (cohead_number=cohist_ordernumber)
+            LEFT OUTER JOIN custtype ON (custtype_id=cust_custtype_id)
+            LEFT OUTER JOIN salesrep ON (salesrep_id=cohist_salesrep_id)
+            LEFT OUTER JOIN shiptoinfo ON (shipto_id=cohist_shipto_id)
+            LEFT OUTER JOIN shipzone ON (shipzone_id=shipto_shipzone_id)
+            LEFT OUTER JOIN saletype ON (saletype_id=cohist_saletype_id)
             LEFT OUTER JOIN itemsite ON (itemsite_id=cohist_itemsite_id)
             LEFT OUTER JOIN site() ON (warehous_id=itemsite_warehous_id)
             LEFT OUTER JOIN item ON (item_id=itemsite_item_id)
             LEFT OUTER JOIN prodcat ON (prodcat_id=item_prodcat_id)
-            LEFT OUTER JOIN shiptoinfo ON (shipto_id=cohist_shipto_id)
-            LEFT OUTER JOIN shipzone ON (shipzone_id=shipto_shipzone_id);
+WHERE  (COALESCE(cohist_misc_type, '') <> 'F')
+  AND  (COALESCE(cohist_misc_type, '') <> 'T')
+     ) AS data;
 
 REVOKE ALL ON TABLE saleshistorymisc FROM PUBLIC;
 GRANT  ALL ON TABLE saleshistorymisc TO GROUP xtrole;
index 42ff347..dd91679 100644 (file)
@@ -5,17 +5,30 @@
 (function () {
   'use strict';
 
+  Object.observe = undefined;
+
   /**
     Abstract check for attribute level privilege access.
 
     @private
   */
   var _canDoAttr = function (action, attribute) {
-    var priv = this.privileges &&
+    var privObject = this.privileges &&
       this.privileges.attribute &&
-      this.privileges.attribute[attribute] &&
-      !_.isUndefined(this.privileges.attribute[attribute][action]) ?
-      this.privileges.attribute[attribute][action] : undefined;
+      this.privileges.attribute[attribute];
+
+    // shim: the way to set an attribute to be non-editable after persist is {update: "false"}
+    // if someone is asking if we can update a READY_NEW model, they're going to be asking
+    // canEdit, which will map to update, but we really know they are interested in the `create`
+    // attribute of the privObject
+    if (privObject && action === "update" && this.isNew() &&
+        privObject.create !== privObject.update) {
+      action = "create";
+    }
+
+    var priv = privObject &&
+      !_.isUndefined(privObject[action]) ?
+      privObject[action] : undefined;
 
     // If there was a privilege then check our access, otherwise assume we have it
     var hasPriv = !_.isUndefined(priv) ? XT.session.getPrivileges().get(priv) : true;
index 4d7b7c5..8294c68 100644 (file)
@@ -14,5 +14,6 @@ depends(
   "characteristic.js",
   "alarm.js",
   "settings.js",
-  "workflow.js"
+  "workflow.js",
+  "router.js"
 );
diff --git a/lib/backbone-x/source/router.js b/lib/backbone-x/source/router.js
new file mode 100644 (file)
index 0000000..520175c
--- /dev/null
@@ -0,0 +1,31 @@
+/*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
+newcap:true, noarg:true, regexp:true, undef:true, trailing:true,
+white:true*/
+/*global XT:true, XM:true, XV:true, Backbone:true, console:true */
+
+(function () {
+
+  XM.BackboneRouter = Backbone.Router.extend({
+
+    routes: {
+      "workspace/:recordType/:id": "workspace"
+    },
+
+    /**
+      @objectName {String} in format sales-order
+     */
+    workspace: function (objectName, id) {
+      var recordType = "XM." + objectName.charAt(0).toUpperCase() +
+        objectName.slice(1).camelize();
+      var inEvent = {
+        workspace: XV.getWorkspace(recordType),
+        id: id
+      };
+      XT.app.waterfallWorkspace(null, inEvent);
+    }
+
+  });
+  XM.backboneRouter = new XM.BackboneRouter();
+
+}());
+
index adb4dc2..02e2565 160000 (submodule)
@@ -1 +1 @@
-Subproject commit adb4dc23d096bb1648b8369e5da0ca39e43b1e0d
+Subproject commit 02e25652e3d81f694919f917fb9eb23105befaeb
index 2f07024..bd18801 100644 (file)
@@ -1,7 +1,7 @@
 /*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
 newcap:true, noarg:true, regexp:true, undef:true, trailing:true,
 white:true*/
-/*global enyo:true, XT:true, _:true, document:true, window:true, XM:true */
+/*global Backbone:true, enyo:true, XT:true, _:true, document:true, window:true, XM:true */
 
 (function () {
 
@@ -343,6 +343,7 @@ white:true*/
         if (!XT.baseCurrency()) {
           this.waterfallNoBaseCurr();
         }
+        Backbone.history.start();
       }
     },
     start: function (debug) {
index 053f9be..29bac3b 100644 (file)
@@ -90,10 +90,11 @@ trailing:true, white:true, strict: false*/
 
     /**
       Add component or array of component view(s) to a view class that
-      has implemented the `extensionsMixin`.
+      has implemented the `ExtensionsMixin`.
 
       Examples of classes that support extensions are:
         * `Workspace`
+        * `List`
         * `ParameterWidget`
 
       @param {String} Class name
index 30b4140..38a3766 100644 (file)
@@ -10,9 +10,6 @@
       font-style: italic;
       color: @blue-gray;
     }
-    &.hyperlink {
-      color: @blue;
-    }
     &.disabled {
       color: @dim-gray;
     }
@@ -68,4 +65,4 @@
   overflow: auto;
   color: @black;
   background-color: @white;
-}
\ No newline at end of file
+}
diff --git a/lib/enyo-x/source/less/characteristics.less b/lib/enyo-x/source/less/characteristics.less
deleted file mode 100644 (file)
index 38eef4d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
-  Characteristics
-*/
-
-.xv-characteristic-picker {
-  border: none;
-  .onyx-picker-decorator .onyx-button {
-    width: 130px;
-  }
-}
-
-.xv-characteristic-item {
-  border-bottom: 1px solid @smoke;
-  .onyx-input-decorator > input {
-    width: 115px;
-    margin-top: 10px;
-    margin-bottom: 10px;
-  }
-  > .xv-input {
-    border: none;
-  }
-}
-
-.xv-characteristic-buttons {
-  margin: 8px;
-}
-
-.xv-characteristic-button {
-  margin-left: 4px;
-  color: @slate-blue;
-  font-size: 24px;
-}
index dd2a6b2..502edbd 100644 (file)
@@ -90,6 +90,7 @@
     .icon-filter {
        color: @black;
        position: absolute;
+       top: 0;
        right: 35px;
     }
   }
   .chart-filterDrawer {
     top: 0px;
   }
+  
+  .map-cluster {
+    width: 40px;
+    height: 40px;
+    background-color: greenyellow;
+    text-align: center;
+    font-size: 24px;
+  }
 
   /*  The chart-filters may not be need as we are using the class xv-pullout
       for styles.  Delete when finished hacking the filter styles.
index 4453ce6..7b5cccc 100644 (file)
@@ -1,6 +1,12 @@
 /*
   Styles relating to the grid box
 */
+@widgetFontSize: 13px;
+@gridIconWidth: 4px;
+@gridIconPadding: 2px;
+@gridFieldDecoratorWidth: 100%;
+@gridFieldWidth: @gridFieldDecoratorWidth - (2 * @decoratorPadding);
+@iconGridFieldWidth: @gridFieldWidth - @gridIconWidth - (2 * @gridIconPadding);
 
 
 /* Entire box including the grid and the summary panel */
   }
 
   .xv-grid-attr {
-    // This limits the text to three lines
-    overflow: hidden;
-    display: -webkit-box;
-    -webkit-line-clamp: 3;
-    -webkit-box-orient: vertical;
+    .xv-limit-description
 
     &.bold {
     font-weight: bold;
       border: 1px solid @bright-orange;
       .xv-grid-column {
         .onyx-input-decorator {
-          .tightened-input-decorator;
+          .tightened-input-decorator(100%);
         }
         .onyx-picker-decorator {
           padding-top: 6px;
             height: 26px;
             padding-top: 3px;
             width: 100%;
-            font-size: 13px;
+            font-size: @widgetFontSize;
           }
         }
         .xv-input {
+          padding-top: 6px;
+          width: @gridFieldDecoratorWidth;
           border: none;
+
         }
-        .xv-picker-label {
+        .xv-label, .xv-flexible-label, .xv-picker-label {
           display: none;
         }
-        .xv-datewidget {
-          margin-right: 10px;
-          padding-top: 0;
-          .onyx-input-decorator {
-            padding: 0;
-            width: 100%;
-            input {
-              width: 85%;
-              font-size: 13px;
-            }
+        .xv-relationwidget {
+          .xv-description {
+            margin: 0;
+            margin-top: 5px;
+          }
+          &.xv-private-item-site-widget {
+            border-bottom: 0;
           }
-        }
-        .xv-numberwidget {
-          padding-top: 6px;
           .onyx-input-decorator {
             .tightened-input-decorator;
           }
         }
-        .xv-combobox {
-          padding-left: 0;
-          input {
-            padding-top: 3px;
-            width: 80px;
-            font-size: 13px;
-          }
-        }
-        .xv-moneywidget {
-          padding-bottom: 0;
+        .xv-datewidget {
           .onyx-input-decorator {
             .tightened-input-decorator;
           }
         }
-        .xv-relationwidget {
+        .xv-combobox {
           .onyx-input-decorator {
-            width: 100%;
-            padding-top: 6px;
-          }
-          .onyx-input {
-            width: 85%;
-            padding-right: 4px;
+            .tightened-input-decorator;
           }
         }
         .xv-useraccount-widget {
-          // Hack: we shouldn't have to force this.
-          .xv-subinput {
+          .xv-input {
             width: 80px;
             height: 16px;
           }
         }
-        .xv-subinput {
-          width: 100%;
-        }
-        .xv-input {
-          padding-top: 6px;
-          width: 100%;
-          border: none;
-        }
-        .xv-label, .xv-flexible-label, .xv-relationwidget-secondarydescription {
-          display: none;
-        }
-        .xv-relationwidget-description {
-          margin: 0;
-          margin-top: 5px;
-        }
-        .xv-private-item-site-widget {
-          border-bottom: 0;
-        }
       }
     }
   }
   }
 }
 
-.tightened-input-decorator (@width: 100%) {
+.tightened-input-decorator (@inputWidth: @iconGridFieldWidth) {
   padding: 0;
-  width: @width;
+  width: @gridFieldDecoratorWidth;
   margin: 0;
   input {
-    width: (@width);
-    font-size: 13px;
+    width: @inputWidth;
+    font-size: @widgetFontSize;
   }
 }
index e5bb712..7c103ee 100644 (file)
     color: @dim-gray;
   }
   &.hyperlink {
-    color: blue;
+    color: @slate-blue;
+    cursor: pointer;
   }
   &.disabled {
     color: @dim-gray;
index 044c9ac..7e92c6b 100644 (file)
   }
 }
 
-.xv-combobox {
-  .onyx-input-decorator {
-    input {
-      width: 145px;
-    }
-  }
-  .icon-sort {
-    color: @slate-blue;
-    vertical-align: middle;
-  }
-}
 .xv-combobox-note {
   padding: 14px 3px 8px 3px;
   text-align: left;
index 5d53c54..6b1b0af 100644 (file)
     width: 100%;
     margin: 0 4px 6px 0;
 
+    .xv-input, .xv-pickerwidget {
+      .onyx-input-decorator {
+        border: none;
+      }
+    }
+
     .xv-buttons {
       text-align: center;
     }
index d6a480f..1810893 100644 (file)
@@ -2,62 +2,30 @@
   Styles relating to RelationWidgets
 */
 
- .xv-relationwidget-completer {
 .xv-relationwidget-completer {
    left: -200px;
    top: 15px;
- }
 }
 
- .xv-completer-sidecar {
 .xv-completer-sidecar {
    color: @blue-gray;
- }
-
- .xv-relationwidget-column {
-   &.left {
-     padding-right: 18px;
-     color: @black;
-     width: 140px;
-   }
- }
+  }
 
- .xv-relationwidget-icon {
 .xv-relationwidget-icon {
    top: 1px;
    left: 8px;
    height: 30px;
    position: relative;
- }
-
- .xv-relationwidget-description {
-   overflow: hidden;
-   // This gives them 3 lines of description
-   display: -webkit-box;
-   -webkit-line-clamp: 3;
-   -webkit-box-orient: vertical;
-   max-width: 250px;
-   margin: 5px 5px 5px 80px;
-   &.disabled {
-     color: @dim-gray;
-   }
-   &.label {
-     text-indent: 0;
-     text-align: right;
-
-   }
-   &.hasLabel {
-     text-indent: 0;
-   }
-   &.hyperlink {
-     color: blue;
   }
- }
 
- .xv-private-item-site-widget {
 .xv-private-item-site-widget {
    border-bottom-color: rgb(170, 170, 170);
    border-bottom-width: 1px;
    border-bottom-style: solid;
- }
 }
 
- /* RelationsEditorBox */
- .xv-relations-editor-box {
 /* RelationsEditorBox */
 .xv-relations-editor-box {
    .xv-groupbox {
      margin-right: 0;
      padding: 0;
    &.panel {
      width: 350px;
    }
- }
 }
 
- /* ListRelationsBox */
- .xv-list-relations-box {
 /* ListRelationsBox */
 .xv-list-relations-box {
    &.panel {
      width: 625px;
    }
- }
 }
 
- .xv-short-relations-box {
 .xv-short-relations-box {
    &.panel {
      width: 500px;
    }
- }
 }
index 40f1005..a2371b6 100644 (file)
 @panelsFontSize: 5em;
 @iconFontSize: 60%;
 @totalsFontSize: 14px;
-@buttonFontSize: 17px;
+@buttonFontSize: 20px;
+@buttonTextFontSize: 17px;
 
 // sizing
 @defaultPanelWidth: 320px;
 @toolbarHeight: 55px;
 @searchLength: 185px;
+// popups
+@maxMessageHeight: 500px;
+@maxMessageWidth: 500px;
 
 // libs
 @import "../../lib/font-awesome/less/font-awesome.less";
@@ -75,6 +79,24 @@ body {
   cursor: default;
 }
 
+a, .hyperlink {
+  color: @slate-blue;
+  cursor: pointer;
+}
+
+.xv-invisible-wrapper {
+  padding: 0;
+  border: none;
+}
+
+  // This gives them 4 lines of description
+.xv-limit-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+}
+
 .xv-app-panel {
   /* Setting this as min-width overrides enyo-narrow 100% */
   width: @defaultPanelWidth;
@@ -137,13 +159,18 @@ body {
 
   .onyx-button {
     margin: 2px;
+    min-height: 40px;
     min-width: 60px;
     background: @button-gray;
     color: @charcoal;
-    font-size: 20px;
+    font-size: @buttonFontSize;
+
+    &[class^="icon-"]:before, &[class*=" icon-"]:before {
+      vertical-align: middle;
+      margin-right: 5px;
+    }
     &.text {
-      font-size: @buttonFontSize;
-      font-family: @baseFont;
+      font-size: @buttonTextFontSize;
     }
     &.selected {
       background: @slate-blue;
@@ -172,13 +199,16 @@ body {
 */
 .xv-popup {
   background: @header-gray;
-  margin: 0;
-  max-height: 400px;
-  width: 400px;
   min-width: @defaultPanelWidth;
-  padding: 7px;
+  padding: 10px;
   text-align: center;
 
+  .message {
+    margin-bottom: 10px;
+    max-height: @maxMessageHeight;
+    max-width: @maxMessageWidth;
+  }
+
   &.xv-groupbox-popup {
     .xv-workspace-container > .xv-workspace > .xv-workspace-panel;
     color: @black;
@@ -244,9 +274,10 @@ body {
   }
 }
 
-.icon-folder-open-alt, .icon-calendar, .icon-sort {
+.icon-folder-open-alt, .icon-calendar, .icon-sort, .icon-angle-up, .icon-angle-down {
   color: @slate-blue;
   vertical-align: middle;
+  text-align: center;
 }
 
 .xv-short-textarea {
@@ -358,8 +389,6 @@ body {
 @import "dashboard.less";
 @import "list.less";
 @import "pullout.less";
-@import "widgets.less";
-@import "characteristics.less";
 @import "relations.less";
 @import "address.less";
 @import "search.less";
diff --git a/lib/enyo-x/source/less/widgets.less b/lib/enyo-x/source/less/widgets.less
deleted file mode 100644 (file)
index 025e556..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
-  Styles relating to misc widgets
-*/
-
-.onyx-input-decorator {
-  border: 0;
-  input {
-    width: 150px;
-  }
-}
-
-.xv-relationwidget, .xv-datewidget {
-  input {
-    width: 135px;
-  }
-}
-
-.xv-numberwidget {
-  input {
-    text-align: right;
-    width: 150px;
-  }
-}
-
-.xv-moneywidget {
-  padding-top: 6px;
-  padding-bottom: 2px;
-
-  .onyx-input-decorator {
-    font-family: @groupboxFont;
-    margin-right: 5px;
-
-    input, .xv-money-label {
-      width: 85px;
-      text-align: right;
-    }
-    &.xv-currency-label {
-      width: 65px;
-    }
-  }
-  .xv-picker-button {
-    width: 65px;
-    padding: 10px 4px;
-  }
-}
-
-.spinner {
-  // this is a label fix since the spinner is so tall
-  .enyo-fittable-columns-layout > * {
-    vertical-align: middle;
-  }
-  .buttons {
-    display: block;
-    padding: 0;
-    margin: 1px 0 1px 10px;
-    width: 20px;
-    height: 20px;
-    background: transparent;
-    color: @slate-blue;
-    font-size: 20px;
-    border: none;
-  }
-  .slider {
-    margin: 15px 10px;
-  }
-  &.xv-numberwidget {
-    input {
-      width: 120px;
-    }
-  }
-}
-
-.xv-dependency-picker {
-  .onyx-picker-decorator {
-    .onyx-button {
-      width: 280px;
-      margin-left: 6px;
-    }
-  }
-}
-
-.xv-dependency-button {
-  color: @slate-blue;
-  font-size: 24px;
-  border: none;
-  background: transparent;
-}
index 90a3739..c00b2ff 100644 (file)
 
       // fix labels with widget refactor
       .xv-label, .xv-decorated-label, .xv-flexible-label {
-        width: @labelWidth !important;
+        width: @labelWidth;
         max-width: 100%;
-        padding: 0 8px 0 6px;
         text-align: right;
+        padding: 0 8px 0 6px;
         vertical-align: middle;
+        &.disabled {
+          color: @dim-gray;
+        }
       }
+
       &.xv-assignment-box {
         .xv-flexible-label, .xv-label {
           width: 200px !important;
       }
 
       .xv-input {
-        border-bottom: 1px solid @smoke;
-        margin: 0px;
+        padding: 4px 0;
+        border-bottom: 1px solid fade(@smoke, 50%);
+
+        .enyo-tool-decorator {
+          max-width: @fieldDecoratorWidth;
+          text-align: left;
+
+          .onyx-icon {
+            display: inline-block;
+            width: @iconWidth;
+            cursor: pointer;
+          }
+        }
+
+        &.xv-textarea {
+          padding: 0;
+          margin: @decoratorPadding;
+          .enyo-tool-decorator {
+            // reset max-width on text area
+            max-width: @defaultPanelWidth;
+          }
+        }
+
+        input {
+          width: @fieldWidth;
+        }
+
+        .xv-icon-decorator {
+          input {
+            width: @iconFieldWidth;
+          }
+          .onyx-icon {
+            padding: @iconPadding;
+          }
+        }
+
+        .onyx-picker-decorator {
+          padding: 0;  // @overrides the input-decorator padding above ^^
+        }
+      }
+
+      /**
+        Styles relating to workspace widgets
+      */
+      .xv-relationwidget {
+        .xv-description {
+          .xv-limit-description;
+
+          max-width: 250px;
+          margin: 5px 5px 5px 80px;
+          font-size: 0.9em;
+
+          &.disabled {
+            color: @dim-gray;
+          }
+        }
+      }
+
+      .xv-spinnerwidget {
+        .xv-icon-decorator {
+          .onyx-icon {
+            display: block;
+            border: none;
+            font-size: 20px;
+            width: 20px;
+            padding: 0 4px 0 4px;
+          }
+          input {
+            width: @iconFieldWidth - @iconPadding;
+          }
+        }
+        .slider {
+          margin: 15px 10px;
+        }
+      }
+
+      .xv-numberwidget {
+        input {
+          text-align: right;
+        }
+      }
+
+      .xv-moneywidget {
+        .enyo-tool-decorator {
+          // reset min/max-width
+          min-width: 90px;
+          max-width: 90px;
+          input {
+            width: 90px;
+          }
+        }
+      }
+
+      .xv-currency-picker {
+        display: inline-block;
+        .enyo-tool-decorator {
+          // reset min/max-width
+          min-width: 65px;
+          max-width: 65px;
+          padding: 10px 4px;
+          .xv-button-text {
+            width: 45px;
+          }
+        }
+      }
+
+      .xv-characteristics-widget {
+        .xv-characteristic-item {
+          border-bottom: 1px solid @smoke;
+          .xv-input {
+            border: none;
+            input {
+              width: 135px;
+            }
+          }
+        }
+        .xv-characteristic-button {
+          text-align: center;
+        }
       }
 
       .enyo-fittable-columns-layout > * {
     }
 
     .onyx-input-decorator {
+      border: 0;
+      input {
+        width: 150px;
+      }
       &.onyx-disabled {
         .disabled;
       }
     }
 
+    // Dependency picker in workflow
+    .xv-dependency-picker {
+      .onyx-picker-decorator {
+        .onyx-button {
+          width: 280px;
+          margin-left: 6px;
+        }
+      }
+    }
+
+    .xv-dependency-button {
+      color: @slate-blue;
+      font-size: 24px;
+      border: none;
+      background: transparent;
+    }
+
     .xv-totals-panel {
       .onyx-input-decorator > input, * {
         font-size: @totalsFontSize;
index 7836159..f123de5 100755 (executable)
@@ -1523,6 +1523,21 @@ body {
   opacity: 0.8;
   cursor: default;
 }
+a,
+.hyperlink {
+  color: #357ec7;
+  cursor: pointer;
+}
+.xv-invisible-wrapper {
+  padding: 0;
+  border: none;
+}
+.xv-limit-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+}
 .xv-app-panel {
   /* Setting this as min-width overrides enyo-narrow 100% */
   width: 320px;
@@ -1579,14 +1594,19 @@ body {
 }
 .xv-buttons .onyx-button {
   margin: 2px;
+  min-height: 40px;
   min-width: 60px;
   background: #e1e1e1;
   color: #666666;
   font-size: 20px;
 }
+.xv-buttons .onyx-button[class^="icon-"]:before,
+.xv-buttons .onyx-button[class*=" icon-"]:before {
+  vertical-align: middle;
+  margin-right: 5px;
+}
 .xv-buttons .onyx-button.text {
   font-size: 17px;
-  font-family: 'Helvetica Neue', Helvetica, 'Nimbus Sans L', Arial, sans-serif;
 }
 .xv-buttons .onyx-button.selected {
   background: #357ec7;
@@ -1608,13 +1628,15 @@ body {
 */
 .xv-popup {
   background: #505050;
-  margin: 0;
-  max-height: 400px;
-  width: 400px;
   min-width: 320px;
-  padding: 7px;
+  padding: 10px;
   text-align: center;
 }
+.xv-popup .message {
+  margin-bottom: 10px;
+  max-height: 500px;
+  max-width: 500px;
+}
 .xv-popup.xv-groupbox-popup {
   width: 320px;
   margin: 0 4px 0 2px;
@@ -1622,6 +1644,9 @@ body {
   background: #f8f8f8;
   text-overflow: ellipsis;
   border: 1px solid #d7d7d7;
+  /**
+        Styles relating to workspace widgets
+      */
   color: #070707;
   padding: 7px;
 }
@@ -1646,19 +1671,110 @@ body {
 .xv-popup.xv-groupbox-popup .xv-label,
 .xv-popup.xv-groupbox-popup .xv-decorated-label,
 .xv-popup.xv-groupbox-popup .xv-flexible-label {
-  width: 120px !important;
+  width: 120px;
   max-width: 100%;
-  padding: 0 8px 0 6px;
   text-align: right;
+  padding: 0 8px 0 6px;
   vertical-align: middle;
 }
+.xv-popup.xv-groupbox-popup .xv-label.disabled,
+.xv-popup.xv-groupbox-popup .xv-decorated-label.disabled,
+.xv-popup.xv-groupbox-popup .xv-flexible-label.disabled {
+  color: #777777;
+}
 .xv-popup.xv-groupbox-popup.xv-assignment-box .xv-flexible-label,
 .xv-popup.xv-groupbox-popup.xv-assignment-box .xv-label {
   width: 200px !important;
 }
 .xv-popup.xv-groupbox-popup .xv-input {
+  padding: 4px 0;
+  border-bottom: 1px solid rgba(215, 215, 215, 0.5);
+}
+.xv-popup.xv-groupbox-popup .xv-input .enyo-tool-decorator {
+  max-width: 180px;
+  text-align: left;
+}
+.xv-popup.xv-groupbox-popup .xv-input .enyo-tool-decorator .onyx-icon {
+  display: inline-block;
+  width: 16px;
+  cursor: pointer;
+}
+.xv-popup.xv-groupbox-popup .xv-input.xv-textarea {
+  padding: 0;
+  margin: 8px;
+}
+.xv-popup.xv-groupbox-popup .xv-input.xv-textarea .enyo-tool-decorator {
+  max-width: 320px;
+}
+.xv-popup.xv-groupbox-popup .xv-input input {
+  width: 164px;
+}
+.xv-popup.xv-groupbox-popup .xv-input .xv-icon-decorator input {
+  width: 140px;
+}
+.xv-popup.xv-groupbox-popup .xv-input .xv-icon-decorator .onyx-icon {
+  padding: 4px;
+}
+.xv-popup.xv-groupbox-popup .xv-input .onyx-picker-decorator {
+  padding: 0;
+}
+.xv-popup.xv-groupbox-popup .xv-relationwidget .xv-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+  max-width: 250px;
+  margin: 5px 5px 5px 80px;
+  font-size: 0.9em;
+}
+.xv-popup.xv-groupbox-popup .xv-relationwidget .xv-description.disabled {
+  color: #777777;
+}
+.xv-popup.xv-groupbox-popup .xv-spinnerwidget .xv-icon-decorator .onyx-icon {
+  display: block;
+  border: none;
+  font-size: 20px;
+  width: 20px;
+  padding: 0 4px 0 4px;
+}
+.xv-popup.xv-groupbox-popup .xv-spinnerwidget .xv-icon-decorator input {
+  width: 136px;
+}
+.xv-popup.xv-groupbox-popup .xv-spinnerwidget .slider {
+  margin: 15px 10px;
+}
+.xv-popup.xv-groupbox-popup .xv-numberwidget input {
+  text-align: right;
+}
+.xv-popup.xv-groupbox-popup .xv-moneywidget .enyo-tool-decorator {
+  min-width: 90px;
+  max-width: 90px;
+}
+.xv-popup.xv-groupbox-popup .xv-moneywidget .enyo-tool-decorator input {
+  width: 90px;
+}
+.xv-popup.xv-groupbox-popup .xv-currency-picker {
+  display: inline-block;
+}
+.xv-popup.xv-groupbox-popup .xv-currency-picker .enyo-tool-decorator {
+  min-width: 65px;
+  max-width: 65px;
+  padding: 10px 4px;
+}
+.xv-popup.xv-groupbox-popup .xv-currency-picker .enyo-tool-decorator .xv-button-text {
+  width: 45px;
+}
+.xv-popup.xv-groupbox-popup .xv-characteristics-widget .xv-characteristic-item {
   border-bottom: 1px solid #d7d7d7;
-  margin: 0px;
+}
+.xv-popup.xv-groupbox-popup .xv-characteristics-widget .xv-characteristic-item .xv-input {
+  border: none;
+}
+.xv-popup.xv-groupbox-popup .xv-characteristics-widget .xv-characteristic-item .xv-input input {
+  width: 135px;
+}
+.xv-popup.xv-groupbox-popup .xv-characteristics-widget .xv-characteristic-button {
+  text-align: center;
 }
 .xv-popup.xv-groupbox-popup .enyo-fittable-columns-layout > * {
   vertical-align: middle;
@@ -1719,9 +1835,12 @@ body {
 }
 .icon-folder-open-alt,
 .icon-calendar,
-.icon-sort {
+.icon-sort,
+.icon-angle-up,
+.icon-angle-down {
   color: #357ec7;
   vertical-align: middle;
+  text-align: center;
 }
 .xv-short-textarea .xv-textarea-input {
   min-height: 0;
@@ -1944,6 +2063,9 @@ body {
   background: #f8f8f8;
   text-overflow: ellipsis;
   border: 1px solid #d7d7d7;
+  /**
+        Styles relating to workspace widgets
+      */
 }
 .xv-workspace-container .xv-workspace .xv-workspace-panel .onyx-groupbox-header {
   padding: 6px 10px;
@@ -1966,27 +2088,134 @@ body {
 .xv-workspace-container .xv-workspace .xv-workspace-panel .xv-label,
 .xv-workspace-container .xv-workspace .xv-workspace-panel .xv-decorated-label,
 .xv-workspace-container .xv-workspace .xv-workspace-panel .xv-flexible-label {
-  width: 120px !important;
+  width: 120px;
   max-width: 100%;
-  padding: 0 8px 0 6px;
   text-align: right;
+  padding: 0 8px 0 6px;
   vertical-align: middle;
 }
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-label.disabled,
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-decorated-label.disabled,
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-flexible-label.disabled {
+  color: #777777;
+}
 .xv-workspace-container .xv-workspace .xv-workspace-panel.xv-assignment-box .xv-flexible-label,
 .xv-workspace-container .xv-workspace .xv-workspace-panel.xv-assignment-box .xv-label {
   width: 200px !important;
 }
 .xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input {
+  padding: 4px 0;
+  border-bottom: 1px solid rgba(215, 215, 215, 0.5);
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input .enyo-tool-decorator {
+  max-width: 180px;
+  text-align: left;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input .enyo-tool-decorator .onyx-icon {
+  display: inline-block;
+  width: 16px;
+  cursor: pointer;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input.xv-textarea {
+  padding: 0;
+  margin: 8px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input.xv-textarea .enyo-tool-decorator {
+  max-width: 320px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input input {
+  width: 164px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input .xv-icon-decorator input {
+  width: 140px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input .xv-icon-decorator .onyx-icon {
+  padding: 4px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-input .onyx-picker-decorator {
+  padding: 0;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-relationwidget .xv-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+  max-width: 250px;
+  margin: 5px 5px 5px 80px;
+  font-size: 0.9em;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-relationwidget .xv-description.disabled {
+  color: #777777;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-spinnerwidget .xv-icon-decorator .onyx-icon {
+  display: block;
+  border: none;
+  font-size: 20px;
+  width: 20px;
+  padding: 0 4px 0 4px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-spinnerwidget .xv-icon-decorator input {
+  width: 136px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-spinnerwidget .slider {
+  margin: 15px 10px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-numberwidget input {
+  text-align: right;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-moneywidget .enyo-tool-decorator {
+  min-width: 90px;
+  max-width: 90px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-moneywidget .enyo-tool-decorator input {
+  width: 90px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-currency-picker {
+  display: inline-block;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-currency-picker .enyo-tool-decorator {
+  min-width: 65px;
+  max-width: 65px;
+  padding: 10px 4px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-currency-picker .enyo-tool-decorator .xv-button-text {
+  width: 45px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-characteristics-widget .xv-characteristic-item {
   border-bottom: 1px solid #d7d7d7;
-  margin: 0px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-characteristics-widget .xv-characteristic-item .xv-input {
+  border: none;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-characteristics-widget .xv-characteristic-item .xv-input input {
+  width: 135px;
+}
+.xv-workspace-container .xv-workspace .xv-workspace-panel .xv-characteristics-widget .xv-characteristic-button {
+  text-align: center;
 }
 .xv-workspace-container .xv-workspace .xv-workspace-panel .enyo-fittable-columns-layout > * {
   vertical-align: middle;
 }
+.xv-workspace-container .xv-workspace .onyx-input-decorator {
+  border: 0;
+}
+.xv-workspace-container .xv-workspace .onyx-input-decorator input {
+  width: 150px;
+}
 .xv-workspace-container .xv-workspace .onyx-input-decorator.onyx-disabled {
   opacity: 0.8;
   cursor: default;
 }
+.xv-workspace-container .xv-workspace .xv-dependency-picker .onyx-picker-decorator .onyx-button {
+  width: 280px;
+  margin-left: 6px;
+}
+.xv-workspace-container .xv-workspace .xv-dependency-button {
+  color: #357ec7;
+  font-size: 24px;
+  border: none;
+  background: transparent;
+}
 .xv-workspace-container .xv-workspace .xv-totals-panel .onyx-input-decorator > input,
 .xv-workspace-container .xv-workspace .xv-totals-panel * {
   font-size: 14px;
@@ -2011,7 +2240,7 @@ body {
         */
 }
 .xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attribute-id {
-  color: blue;
+  color: #357ec7;
   font-weight: bold;
   cursor: pointer;
 }
@@ -2069,13 +2298,6 @@ body {
 .xv-picker-label.disabled {
   color: #777777;
 }
-.xv-combobox .onyx-input-decorator input {
-  width: 145px;
-}
-.xv-combobox .icon-sort {
-  color: #357ec7;
-  vertical-align: middle;
-}
 .xv-combobox-note {
   padding: 14px 3px 8px 3px;
   text-align: left;
@@ -2108,13 +2330,7 @@ body {
 .xv-grid-box .xv-scroller {
   background: #f8f8f8;
 }
-.xv-grid-box .xv-grid-attr {
-  overflow: hidden;
-  display: -webkit-box;
-  -webkit-line-clamp: 3;
-  -webkit-box-orient: vertical;
-}
-.xv-grid-box .xv-grid-attr.bold {
+.xv-limit-description .xv-grid-box .xv-grid-attr.bold {
   font-weight: bold;
 }
 .xv-grid-box .xv-grid-attr.error {
@@ -2241,87 +2457,53 @@ body {
   font-size: 13px;
 }
 .xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-input {
+  padding-top: 6px;
+  width: 100%;
   border: none;
 }
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-label,
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-flexible-label,
 .xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-picker-label {
   display: none;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-datewidget {
-  margin-right: 10px;
-  padding-top: 0;
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget .xv-description {
+  margin: 0;
+  margin-top: 5px;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-datewidget .onyx-input-decorator {
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget.xv-private-item-site-widget {
+  border-bottom: 0;
+}
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget .onyx-input-decorator {
   padding: 0;
   width: 100%;
+  margin: 0;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-datewidget .onyx-input-decorator input {
-  width: 85%;
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget .onyx-input-decorator input {
+  width: 76%;
   font-size: 13px;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-numberwidget {
-  padding-top: 6px;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-numberwidget .onyx-input-decorator {
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-datewidget .onyx-input-decorator {
   padding: 0;
   width: 100%;
   margin: 0;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-numberwidget .onyx-input-decorator input {
-  width: 100%;
-  font-size: 13px;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-combobox {
-  padding-left: 0;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-combobox input {
-  padding-top: 3px;
-  width: 80px;
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-datewidget .onyx-input-decorator input {
+  width: 76%;
   font-size: 13px;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-moneywidget {
-  padding-bottom: 0;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-moneywidget .onyx-input-decorator {
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-combobox .onyx-input-decorator {
   padding: 0;
   width: 100%;
   margin: 0;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-moneywidget .onyx-input-decorator input {
-  width: 100%;
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-combobox .onyx-input-decorator input {
+  width: 76%;
   font-size: 13px;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget .onyx-input-decorator {
-  width: 100%;
-  padding-top: 6px;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget .onyx-input {
-  width: 85%;
-  padding-right: 4px;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-useraccount-widget .xv-subinput {
+.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-useraccount-widget .xv-input {
   width: 80px;
   height: 16px;
 }
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-subinput {
-  width: 100%;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-input {
-  padding-top: 6px;
-  width: 100%;
-  border: none;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-label,
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-flexible-label,
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget-secondarydescription {
-  display: none;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-relationwidget-description {
-  margin: 0;
-  margin-top: 5px;
-}
-.xv-grid-box .xv-grid-row.selected .xv-grid-column .xv-private-item-site-widget {
-  border-bottom: 0;
-}
 .xv-grid-box.xv-groupbox .xv-sales-summary-panel {
   border: none;
   margin-top: 0;
@@ -2473,6 +2655,7 @@ body {
 .selectable-chart .chart-title-bar .icon-filter {
   color: #070707;
   position: absolute;
+  top: 0;
   right: 35px;
 }
 .selectable-chart .chart-bottom {
@@ -2497,6 +2680,13 @@ body {
 .selectable-chart .chart-filterDrawer {
   top: 0px;
 }
+.selectable-chart .map-cluster {
+  width: 40px;
+  height: 40px;
+  background-color: greenyellow;
+  text-align: center;
+  font-size: 24px;
+}
 /**
   Styles relating to Lists
 */
@@ -2750,7 +2940,8 @@ body {
   color: #777777;
 }
 .xv-list-attr.hyperlink {
-  color: blue;
+  color: #357ec7;
+  cursor: pointer;
 }
 .xv-list-attr.disabled {
   color: #777777;
@@ -2827,6 +3018,9 @@ body {
   background: #f8f8f8;
   text-overflow: ellipsis;
   border: 1px solid #d7d7d7;
+  /**
+        Styles relating to workspace widgets
+      */
   width: 100%;
   margin: 0 4px 6px 0;
 }
@@ -2851,139 +3045,139 @@ body {
 .xv-pullout .xv-parameter-panel .xv-label,
 .xv-pullout .xv-parameter-panel .xv-decorated-label,
 .xv-pullout .xv-parameter-panel .xv-flexible-label {
-  width: 120px !important;
+  width: 120px;
   max-width: 100%;
-  padding: 0 8px 0 6px;
   text-align: right;
+  padding: 0 8px 0 6px;
   vertical-align: middle;
 }
+.xv-pullout .xv-parameter-panel .xv-label.disabled,
+.xv-pullout .xv-parameter-panel .xv-decorated-label.disabled,
+.xv-pullout .xv-parameter-panel .xv-flexible-label.disabled {
+  color: #777777;
+}
 .xv-pullout .xv-parameter-panel.xv-assignment-box .xv-flexible-label,
 .xv-pullout .xv-parameter-panel.xv-assignment-box .xv-label {
   width: 200px !important;
 }
 .xv-pullout .xv-parameter-panel .xv-input {
-  border-bottom: 1px solid #d7d7d7;
-  margin: 0px;
+  padding: 4px 0;
+  border-bottom: 1px solid rgba(215, 215, 215, 0.5);
 }
-.xv-pullout .xv-parameter-panel .enyo-fittable-columns-layout > * {
-  vertical-align: middle;
+.xv-pullout .xv-parameter-panel .xv-input .enyo-tool-decorator {
+  max-width: 180px;
+  text-align: left;
 }
-.xv-pullout .xv-parameter-panel .xv-buttons {
-  text-align: center;
+.xv-pullout .xv-parameter-panel .xv-input .enyo-tool-decorator .onyx-icon {
+  display: inline-block;
+  width: 16px;
+  cursor: pointer;
 }
-.xv-pullout .xv-parameter-panel .xv-filter-form .xv-list {
-  height: 150px;
+.xv-pullout .xv-parameter-panel .xv-input.xv-textarea {
+  padding: 0;
+  margin: 8px;
 }
-.xv-pullout .help-panel {
-  border: none;
-  height: 100%;
-  width: 100%;
+.xv-pullout .xv-parameter-panel .xv-input.xv-textarea .enyo-tool-decorator {
+  max-width: 320px;
 }
-.xv-pullout .history-panel .xv-list-item {
-  padding: 12px 10px;
-  color: #0e0e0e;
-  background-color: #fdfdfd;
-  border-bottom: 1px solid #d7d7d7;
+.xv-pullout .xv-parameter-panel .xv-input input {
+  width: 164px;
 }
-.xv-pullout .history-panel .xv-list-item.onyx-selected {
-  background-color: #357ec7;
-  color: #fdfdfd;
-  border-bottom: 2px solid #d8d8d8;
+.xv-pullout .xv-parameter-panel .xv-input .xv-icon-decorator input {
+  width: 140px;
 }
-/**
-  Styles relating to misc widgets
-*/
-.onyx-input-decorator {
-  border: 0;
+.xv-pullout .xv-parameter-panel .xv-input .xv-icon-decorator .onyx-icon {
+  padding: 4px;
 }
-.onyx-input-decorator input {
-  width: 150px;
+.xv-pullout .xv-parameter-panel .xv-input .onyx-picker-decorator {
+  padding: 0;
 }
-.xv-relationwidget input,
-.xv-datewidget input {
-  width: 135px;
+.xv-pullout .xv-parameter-panel .xv-relationwidget .xv-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+  max-width: 250px;
+  margin: 5px 5px 5px 80px;
+  font-size: 0.9em;
 }
-.xv-numberwidget input {
-  text-align: right;
-  width: 150px;
+.xv-pullout .xv-parameter-panel .xv-relationwidget .xv-description.disabled {
+  color: #777777;
 }
-.xv-moneywidget {
-  padding-top: 6px;
-  padding-bottom: 2px;
+.xv-pullout .xv-parameter-panel .xv-spinnerwidget .xv-icon-decorator .onyx-icon {
+  display: block;
+  border: none;
+  font-size: 20px;
+  width: 20px;
+  padding: 0 4px 0 4px;
 }
-.xv-moneywidget .onyx-input-decorator {
-  font-family: "Lucida Sans Unicode", "Lucida Grande", arial, sans-serif;
-  margin-right: 5px;
+.xv-pullout .xv-parameter-panel .xv-spinnerwidget .xv-icon-decorator input {
+  width: 136px;
 }
-.xv-moneywidget .onyx-input-decorator input,
-.xv-moneywidget .onyx-input-decorator .xv-money-label {
-  width: 85px;
+.xv-pullout .xv-parameter-panel .xv-spinnerwidget .slider {
+  margin: 15px 10px;
+}
+.xv-pullout .xv-parameter-panel .xv-numberwidget input {
   text-align: right;
 }
-.xv-moneywidget .onyx-input-decorator.xv-currency-label {
-  width: 65px;
+.xv-pullout .xv-parameter-panel .xv-moneywidget .enyo-tool-decorator {
+  min-width: 90px;
+  max-width: 90px;
+}
+.xv-pullout .xv-parameter-panel .xv-moneywidget .enyo-tool-decorator input {
+  width: 90px;
+}
+.xv-pullout .xv-parameter-panel .xv-currency-picker {
+  display: inline-block;
 }
-.xv-moneywidget .xv-picker-button {
-  width: 65px;
+.xv-pullout .xv-parameter-panel .xv-currency-picker .enyo-tool-decorator {
+  min-width: 65px;
+  max-width: 65px;
   padding: 10px 4px;
 }
-.spinner .enyo-fittable-columns-layout > * {
-  vertical-align: middle;
+.xv-pullout .xv-parameter-panel .xv-currency-picker .enyo-tool-decorator .xv-button-text {
+  width: 45px;
 }
-.spinner .buttons {
-  display: block;
-  padding: 0;
-  margin: 1px 0 1px 10px;
-  width: 20px;
-  height: 20px;
-  background: transparent;
-  color: #357ec7;
-  font-size: 20px;
-  border: none;
+.xv-pullout .xv-parameter-panel .xv-characteristics-widget .xv-characteristic-item {
+  border-bottom: 1px solid #d7d7d7;
 }
-.spinner .slider {
-  margin: 15px 10px;
+.xv-pullout .xv-parameter-panel .xv-characteristics-widget .xv-characteristic-item .xv-input {
+  border: none;
 }
-.spinner.xv-numberwidget input {
-  width: 120px;
+.xv-pullout .xv-parameter-panel .xv-characteristics-widget .xv-characteristic-item .xv-input input {
+  width: 135px;
 }
-.xv-dependency-picker .onyx-picker-decorator .onyx-button {
-  width: 280px;
-  margin-left: 6px;
+.xv-pullout .xv-parameter-panel .xv-characteristics-widget .xv-characteristic-button {
+  text-align: center;
 }
-.xv-dependency-button {
-  color: #357ec7;
-  font-size: 24px;
-  border: none;
-  background: transparent;
+.xv-pullout .xv-parameter-panel .enyo-fittable-columns-layout > * {
+  vertical-align: middle;
 }
-/**
-  Characteristics
-*/
-.xv-characteristic-picker {
+.xv-pullout .xv-parameter-panel .xv-input .onyx-input-decorator,
+.xv-pullout .xv-parameter-panel .xv-pickerwidget .onyx-input-decorator {
   border: none;
 }
-.xv-characteristic-picker .onyx-picker-decorator .onyx-button {
-  width: 130px;
-}
-.xv-characteristic-item {
-  border-bottom: 1px solid #d7d7d7;
+.xv-pullout .xv-parameter-panel .xv-buttons {
+  text-align: center;
 }
-.xv-characteristic-item .onyx-input-decorator > input {
-  width: 115px;
-  margin-top: 10px;
-  margin-bottom: 10px;
+.xv-pullout .xv-parameter-panel .xv-filter-form .xv-list {
+  height: 150px;
 }
-.xv-characteristic-item > .xv-input {
+.xv-pullout .help-panel {
   border: none;
+  height: 100%;
+  width: 100%;
 }
-.xv-characteristic-buttons {
-  margin: 8px;
+.xv-pullout .history-panel .xv-list-item {
+  padding: 12px 10px;
+  color: #0e0e0e;
+  background-color: #fdfdfd;
+  border-bottom: 1px solid #d7d7d7;
 }
-.xv-characteristic-button {
-  margin-left: 4px;
-  color: #357ec7;
-  font-size: 24px;
+.xv-pullout .history-panel .xv-list-item.onyx-selected {
+  background-color: #357ec7;
+  color: #fdfdfd;
+  border-bottom: 2px solid #d8d8d8;
 }
 /**
   Styles relating to RelationWidgets
@@ -2995,38 +3189,12 @@ body {
 .xv-completer-sidecar {
   color: #93a1a1;
 }
-.xv-relationwidget-column.left {
-  padding-right: 18px;
-  color: #070707;
-  width: 140px;
-}
 .xv-relationwidget-icon {
   top: 1px;
   left: 8px;
   height: 30px;
   position: relative;
 }
-.xv-relationwidget-description {
-  overflow: hidden;
-  display: -webkit-box;
-  -webkit-line-clamp: 3;
-  -webkit-box-orient: vertical;
-  max-width: 250px;
-  margin: 5px 5px 5px 80px;
-}
-.xv-relationwidget-description.disabled {
-  color: #777777;
-}
-.xv-relationwidget-description.label {
-  text-indent: 0;
-  text-align: right;
-}
-.xv-relationwidget-description.hasLabel {
-  text-indent: 0;
-}
-.xv-relationwidget-description.hyperlink {
-  color: blue;
-}
 .xv-private-item-site-widget {
   border-bottom-color: #aaaaaa;
   border-bottom-width: 1px;
@@ -3061,9 +3229,6 @@ body {
   font-style: italic;
   color: #93a1a1;
 }
-.xv-addresswidget .xv-addresswidget-viewer.hyperlink {
-  color: #0000ff;
-}
 .xv-addresswidget .xv-addresswidget-viewer.disabled {
   color: #777777;
 }
@@ -3135,6 +3300,9 @@ body {
   background: #f8f8f8;
   text-overflow: ellipsis;
   border: 1px solid #d7d7d7;
+  /**
+        Styles relating to workspace widgets
+      */
   width: 100%;
   margin: 0 4px 6px 0;
 }
@@ -3159,23 +3327,118 @@ body {
 .xv-search .xv-search-container .xv-label,
 .xv-search .xv-search-container .xv-decorated-label,
 .xv-search .xv-search-container .xv-flexible-label {
-  width: 120px !important;
+  width: 120px;
   max-width: 100%;
-  padding: 0 8px 0 6px;
   text-align: right;
+  padding: 0 8px 0 6px;
   vertical-align: middle;
 }
+.xv-search .xv-search-container .xv-label.disabled,
+.xv-search .xv-search-container .xv-decorated-label.disabled,
+.xv-search .xv-search-container .xv-flexible-label.disabled {
+  color: #777777;
+}
 .xv-search .xv-search-container.xv-assignment-box .xv-flexible-label,
 .xv-search .xv-search-container.xv-assignment-box .xv-label {
   width: 200px !important;
 }
 .xv-search .xv-search-container .xv-input {
+  padding: 4px 0;
+  border-bottom: 1px solid rgba(215, 215, 215, 0.5);
+}
+.xv-search .xv-search-container .xv-input .enyo-tool-decorator {
+  max-width: 180px;
+  text-align: left;
+}
+.xv-search .xv-search-container .xv-input .enyo-tool-decorator .onyx-icon {
+  display: inline-block;
+  width: 16px;
+  cursor: pointer;
+}
+.xv-search .xv-search-container .xv-input.xv-textarea {
+  padding: 0;
+  margin: 8px;
+}
+.xv-search .xv-search-container .xv-input.xv-textarea .enyo-tool-decorator {
+  max-width: 320px;
+}
+.xv-search .xv-search-container .xv-input input {
+  width: 164px;
+}
+.xv-search .xv-search-container .xv-input .xv-icon-decorator input {
+  width: 140px;
+}
+.xv-search .xv-search-container .xv-input .xv-icon-decorator .onyx-icon {
+  padding: 4px;
+}
+.xv-search .xv-search-container .xv-input .onyx-picker-decorator {
+  padding: 0;
+}
+.xv-search .xv-search-container .xv-relationwidget .xv-description {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+  max-width: 250px;
+  margin: 5px 5px 5px 80px;
+  font-size: 0.9em;
+}
+.xv-search .xv-search-container .xv-relationwidget .xv-description.disabled {
+  color: #777777;
+}
+.xv-search .xv-search-container .xv-spinnerwidget .xv-icon-decorator .onyx-icon {
+  display: block;
+  border: none;
+  font-size: 20px;
+  width: 20px;
+  padding: 0 4px 0 4px;
+}
+.xv-search .xv-search-container .xv-spinnerwidget .xv-icon-decorator input {
+  width: 136px;
+}
+.xv-search .xv-search-container .xv-spinnerwidget .slider {
+  margin: 15px 10px;
+}
+.xv-search .xv-search-container .xv-numberwidget input {
+  text-align: right;
+}
+.xv-search .xv-search-container .xv-moneywidget .enyo-tool-decorator {
+  min-width: 90px;
+  max-width: 90px;
+}
+.xv-search .xv-search-container .xv-moneywidget .enyo-tool-decorator input {
+  width: 90px;
+}
+.xv-search .xv-search-container .xv-currency-picker {
+  display: inline-block;
+}
+.xv-search .xv-search-container .xv-currency-picker .enyo-tool-decorator {
+  min-width: 65px;
+  max-width: 65px;
+  padding: 10px 4px;
+}
+.xv-search .xv-search-container .xv-currency-picker .enyo-tool-decorator .xv-button-text {
+  width: 45px;
+}
+.xv-search .xv-search-container .xv-characteristics-widget .xv-characteristic-item {
   border-bottom: 1px solid #d7d7d7;
-  margin: 0px;
+}
+.xv-search .xv-search-container .xv-characteristics-widget .xv-characteristic-item .xv-input {
+  border: none;
+}
+.xv-search .xv-search-container .xv-characteristics-widget .xv-characteristic-item .xv-input input {
+  width: 135px;
+}
+.xv-search .xv-search-container .xv-characteristics-widget .xv-characteristic-button {
+  text-align: center;
 }
 .xv-search .xv-search-container .enyo-fittable-columns-layout > * {
   vertical-align: middle;
 }
+.xv-search .xv-search-container .xv-input .onyx-input-decorator,
+.xv-search .xv-search-container .xv-pickerwidget .onyx-input-decorator {
+  border: none;
+}
 .xv-search .xv-search-container .xv-buttons {
   text-align: center;
 }
index a09a2a1..bb3d0e1 100644 (file)
@@ -152,11 +152,24 @@ trailing:true, white:true*/
       return this.inherited(arguments);
     },
     /**
-      Delete the model of the selected item and remove it from the list
+      Popup confirmation, Delete the model of the selected item and remove it from the list.
     */
     deleteItem: function () {
-      this.getCollection().at(this.getModelIndex()).destroy();
-      this.renderWorkspace();
+      var model = this.getCollection().at(this.getModelIndex()),
+        message = "_unsavedChanges".loc() + " " + "_saveYourWork?".loc(),
+        callback = function (response) {
+          if (response.answer) {
+            this.getActive().doPrevious();
+            // Waterfall down event - handled by lineItem grid box's valueChange function which "refreshes" the list
+            model.on("statusChange", this.waterfall("onChildWorkspaceValueChange"));
+            model.destroy();
+          }
+        };
+      this.doNotify({
+        type: XM.Model.YES_NO_CANCEL,
+        message: "_deleteLine?".loc(),
+        callback: callback
+      });
     },
     /**
       Add a new model to the collection and bring up a blank editor to fill it in
index ecdd49e..6a49dc5 100644 (file)
@@ -246,7 +246,8 @@ trailing:true, white:true, strict: false*/
       ontap: "buttonTapped",
       onEnterOut: "enterOut",
       onMoveUp: "moveUp",
-      onMoveDown: "moveDown"
+      onMoveDown: "moveDown",
+      onChildWorkspaceValueChange: "valueChanged"
     },
     published: {
       attr: null,
@@ -351,9 +352,10 @@ trailing:true, white:true, strict: false*/
         name: "navigationButtonPanel",
         classes: "xv-buttons",
         components: [
-          {kind: "onyx.Button", name: "newButton", ontap: "newItem", classes: "icon-plus"},
+          {kind: "onyx.Button", name: "newButton", ontap: "newItem", content: "_new".loc(),
+            classes: "icon-plus text"},
           {kind: "onyx.Button", name: "exportButton", ontap: "exportAttr",
-           icon: "share", content: "_export".loc(), classes: "icon-share"}
+            classes: "icon-share text", content: "_export".loc()}
         ]
       });
 
@@ -371,6 +373,10 @@ trailing:true, white:true, strict: false*/
       this.inherited(arguments);
       this.createComponents(this.buildComponents());
     },
+    allRowsSaved: function () {
+      return _.every(this.getValue().models,
+                     function (model) { return model.isReadyClean(); });
+    },
     buttonTapped: function (inSender, inEvent) {
       var editor = this.$.editableGridRow,
         model,
@@ -534,8 +540,11 @@ trailing:true, white:true, strict: false*/
       this.doExportAttr({ attr: gridbox.attr });
     },
     refreshLists: function () {
+      var collection = this.getValue();
       this.$.aboveGridList.refresh();
       this.$.belowGridList.refresh();
+      this.$.exportButton.setDisabled(! this.allRowsSaved() ||
+                                      ! collection.length);
     },
     reset: function () {
       this.setEditableIndex(null);
@@ -576,6 +585,11 @@ trailing:true, white:true, strict: false*/
       this._setProperty("value", value, "valueChanged");
 
       collection = value;
+      if (this.getEditableIndex() !== null) {
+        // do not try to sort while the user is entering data
+        return;
+      }
+
       if (orderBy && !collection.comparator) {
         collection.comparator = function (a, b) {
           var aval,
@@ -623,6 +637,9 @@ trailing:true, white:true, strict: false*/
       if (this.$.summaryPanel) {
         this.$.summaryPanel.setValue(model);
       }
+
+      this.$.exportButton.setDisabled(! this.allRowsSaved() ||
+                                      ! collection.length);
     }
   });
 }());
index aff8026..b7e3fa9 100644 (file)
@@ -21,7 +21,7 @@ trailing:true, white:true, strict:false*/
     Note: enyo.List includes a scroller; therefore, XV.List should not be placed inside a scroller.
     @extends XV.ListBase
    */
-  enyo.kind(/** @lends XV.List# */{
+  enyo.kind(_.extend(/** @lends XV.List# */{
     name: "XV.List",
     kind: "XV.ListBase",
     classes: "xv-list",
@@ -106,6 +106,7 @@ trailing:true, white:true, strict:false*/
      */
     create: function () {
       this.inherited(arguments);
+      this.processExtensions();
       var actions = this.getActions() || [],
         deleteAction = _.findWhere(actions, {"name": "delete"}),
         privilege,
@@ -758,6 +759,6 @@ trailing:true, white:true, strict:false*/
         }
       }
     }
-  });
+  }, XV.ExtensionsMixin));
 
 }());
index 6005410..0144f5e 100644 (file)
@@ -6,13 +6,16 @@ trailing:true, white:true, strict:false*/
 (function () {
 
   /**
+    @name XV.ListBase
+    @class
     XV.ListBase contains functionality shared between lists that has to do with
     formatting and action menu handling.
 
     @extends enyo.List
     @extends XV.FormattingMixin
   */
-  enyo.kind(_.extend({
+  enyo.kind(_.extend(
+    /** @lends XV.ListBase */{
     name: "XV.ListBase",
     kind: "List",
     published: {
index ec885ff..f04a7a7 100644 (file)
@@ -98,7 +98,10 @@ trailing:true, white:true, strict: false*/
     @todo Document the controlValueChanged method.
     */
     controlValueChanged: function () {
-      this.$.list.refresh();
+      // this is getting called before the list is created
+      if (this.$.list) {
+        this.$.list.refresh();
+      }
       return true;
     },
     /**
index dff7f03..7130a80 100644 (file)
@@ -38,24 +38,32 @@ trailing:true, white:true*/
         {name: "startupProgressBar", kind: "onyx.ProgressBar",
           classes: "xv-startup-progress  onyx-progress-button", progress: 0}
       ]},
-      {kind: "onyx.Popup", name: "notifyPopup", centered: true,
+      {kind: "onyx.Popup", name: "notifyPopup", classes: "xv-popup", centered: true,
         onHide: "notifyHidden",
         modal: true, floating: true, scrim: true, components: [
-        {name: "notifyMessage"},
-        {tag: "br"},
-        {kind: "onyx.Button", content: "_ok".loc(), name: "notifyOk", ontap: "notifyTap",
-          classes: "xv-popup-button", showing: false},
-        {kind: "onyx.Button", content: "_yes".loc(), name: "notifyYes", ontap: "notifyTap",
-          classes: "xv-popup-button", showing: false},
-        {kind: "onyx.Button", content: "_no".loc(), name: "notifyNo", ontap: "notifyTap",
-          classes: "xv-popup-button", showing: false},
-        {kind: "onyx.Button", content: "_cancel".loc(), name: "notifyCancel", ontap: "notifyTap",
-          classes: "xv-popup-button", showing: false}
+        {name: "notifyMessage", classes: "message"},
+        {classes: "xv-buttons", name: "notifyButtons", components: [
+          {kind: "onyx.Button", content: "_ok".loc(), name: "notifyOk", ontap: "notifyTap",
+            showing: false, classes: "text"},
+          {kind: "onyx.Button", content: "_yes".loc(), name: "notifyYes", ontap: "notifyTap",
+            showing: false, classes: "text"},
+          {kind: "onyx.Button", content: "_no".loc(), name: "notifyNo", ontap: "notifyTap",
+            showing: false, classes: "text"},
+          {kind: "onyx.Button", content: "_cancel".loc(), name: "notifyCancel", ontap: "notifyTap",
+            showing: false, classes: "text"}
+        ]}
       ]},
       {kind: "onyx.Popup", name: "popupWorkspace", classes: "xv-popup xv-groupbox-popup", centered: true,
         autoDismiss: false, modal: true, floating: true, scrim: true},
       {name: "navigator", kind: "XV.Navigator"}
     ],
+    resizeHandler: function () {
+      this.inherited(arguments);
+      if (this.$.notifyPopup.showing) {
+        // This is a fix for an enyo bug that renders the popup as clear
+        this.$.notifyPopup.applyStyle("opacity", 1);
+      }
+    },
     activate: function () {
       this.goToNavigator();
       this.$.navigator.activate();
@@ -172,9 +180,7 @@ trailing:true, white:true*/
       return this.$.navigator;
     },
     getNotifyButtons: function () {
-      return _.filter(this.$, function (control) {
-        return control.name.substring(0, 6) === 'notify' && control.kind === 'onyx.Button';
-      });
+      return this.$.notifyButtons.controls;
     },
     getStartupProgressBar: function () {
       return this.$.startupProgressBar;
@@ -252,19 +258,10 @@ trailing:true, white:true*/
       inEvent.type = inEvent.type || XM.Model.NOTICE;
 
       // show the appropriate buttons
-      _.each(this.$.notifyPopup.children, function (component) {
-        if (component.kind !== "onyx.Button") {
-          // not a button: do nothing.
-        } else if (_.indexOf(typeToButtonMap[String(inEvent.type)], component.name) >= 0) {
-          // in the show-me array, so show
-          component.setShowing(true);
-        } else {
-          // not in the show-me array, so hide
-          component.setShowing(false);
-        }
+      _.each(this.getNotifyButtons(), function (component) {
+        component.setShowing(_.indexOf(typeToButtonMap[String(inEvent.type)], component.name) >= 0);
       });
 
-
       // allow custom button text
       this.$.notifyYes.setContent(inEvent.yesLabel || "_yes".loc());
       this.$.notifyNo.setContent(inEvent.noLabel || "_no".loc());
@@ -275,7 +272,7 @@ trailing:true, white:true*/
       // it's the OK button unless it's a 2- or 3- way question, in which case it's YES
       this._activeNotify = inEvent.type === XM.Model.QUESTION || inEvent.type === XM.Model.YES_NO_CANCEL ? 1 : 0;
       _.each(this.getNotifyButtons(), function (button, index) {
-        button.addRemoveClass("onyx-blue", index === that._activeNotify);
+        button.addRemoveClass("selected", index === that._activeNotify);
       });
 
       // delete out any previously added customComponents/customComponentControls
@@ -296,9 +293,9 @@ trailing:true, white:true*/
       // Add the custom component
       if (inEvent.component) {
         inEvent.component.name = "customComponent";
-        inEvent.component.addBefore = this.$.notifyOk;
+        // can add styling class here instead of inline css
+        inEvent.component.addBefore = this.$.notifyButtons;
         this.$.notifyPopup.createComponent(inEvent.component);
-        this.$.notifyPopup.$.customComponent.addStyles("color:black;");
         if (inEvent.componentModel) {
           this.$.notifyPopup.$.customComponent.setValue(inEvent.componentModel);
         }
@@ -307,7 +304,8 @@ trailing:true, white:true*/
       this._notifyDone = false;
       this.$.notifyPopup.render();
       this.$.notifyPopup.show();
-      this.$.notifyPopup.applyStyle("opacity", 1); // XXX not sure why this hack is necessary.
+      // Without this fix, the popup renders transparent
+      this.$.notifyPopup.applyStyle("opacity", 1);
     },
     notifyHidden: function () {
       if (!this._notifyDone) {
@@ -325,7 +323,7 @@ trailing:true, white:true*/
 
       } else if (keyCode === 37 || (keyCode === 9 && isShift)) {
         // left or shift-tab
-        notifyButtons[activeIndex].removeClass("onyx-blue");
+        notifyButtons[activeIndex].removeClass("selected");
         for (nextShowing = activeIndex - 1; nextShowing >= 0; nextShowing--) {
           if (nextShowing === 0 && !notifyButtons[nextShowing].showing) {
             // there are no showing buttons to the left
@@ -340,11 +338,11 @@ trailing:true, white:true*/
           activeIndex = nextShowing;
         }
         this._activeNotify = activeIndex;
-        notifyButtons[activeIndex].addClass("onyx-blue");
+        notifyButtons[activeIndex].addClass("selected");
 
       } else if (keyCode === 39 || keyCode === 9) {
         // right or tab
-        notifyButtons[activeIndex].removeClass("onyx-blue");
+        notifyButtons[activeIndex].removeClass("selected");
         for (nextShowing = activeIndex + 1; nextShowing < notifyButtons.length; nextShowing++) {
           if (nextShowing + 1 === notifyButtons.length && !notifyButtons[nextShowing].showing) {
             // there are no showing buttons to the right
@@ -360,7 +358,7 @@ trailing:true, white:true*/
         }
         this._activeNotify = activeIndex;
 
-        notifyButtons[activeIndex].addClass("onyx-blue");
+        notifyButtons[activeIndex].addClass("selected");
       }
     },
     /**
@@ -441,27 +439,31 @@ trailing:true, white:true*/
         maxHeight: "400px",
         horizontal: "hidden"
       }, {owner: this});
-      this.$.popupWorkspace.createComponent({name: "workspace", kind: inEvent.workspace, container: this.$.popupScroller});
+      this.$.popupWorkspace.createComponent({name: "workspace", kind: inEvent.workspace,
+        container: this.$.popupScroller});
+      // TODO: inline css - git rid of it!
       this.$.popupWorkspace.$.workspace.addStyles("color:black;");
       this.$.popupWorkspace.$.workspace.setValue(inEvent.model);
-      this.$.popupWorkspace.createComponent({
+      // create button bar
+      this.$.popupWorkspace.createComponent({classes: "xv-buttons", name: "workspaceButtons"}, {owner: this});
+      this.$.workspaceButtons.createComponents([{
         kind: "onyx.Button",
         content: "_save".loc(),
         name: "popupWorkspaceSave",
         ontap: "popupWorkspaceTap",
-        classes: "onyx-blue xv-popup-button"
-      }, {owner: this});
-      this.$.popupWorkspace.createComponent({
+        classes: "selected text"
+      },
+      {
         kind: "onyx.Button",
         content: "_cancel".loc(),
         name: "popupWorkspaceCancel",
         ontap: "popupWorkspaceTap",
-        classes: "xv-popup-button"
-      }, {owner: this});
-
+        classes: "text"
+      }], {owner: this});
       this.$.popupWorkspace.render();
       this.$.popupWorkspace.show();
-      this.$.popupWorkspace.applyStyle("opacity", 1); // XXX not sure why this hack is necessary.
+      // Without this fix, the popup renders transparent
+      this.$.popupWorkspace.applyStyle("opacity", 1);
     },
     popupWorkspaceTap: function (inSender, inEvent) {
       var model = this.$.popupWorkspace.$.workspace.value,
index 2eae521..8fdaa6c 100644 (file)
@@ -514,6 +514,9 @@ trailing:true, white:true, strict: false*/
       } else {
         attrs[Klass.prototype.idAttribute] = recordId;
         this.setValue(Klass.findOrCreate(attrs));
+        XM.backboneRouter.navigate("workspace/" +
+          this.value.recordType.substring(3).decamelize().replace(/_/g, "-") +
+          "/" + recordId);
       }
       _setBindings(this, "on");
       this.fetch();
@@ -854,6 +857,7 @@ trailing:true, white:true, strict: false*/
         model.revert();
       }
 
+      XM.backboneRouter.navigate("");
       if (model && model.hasLockKey && model.hasLockKey()) {
         model.releaseLock({
           success: function () {
index 84be7c4..fd2ae2c 100644 (file)
@@ -19,7 +19,6 @@ white:true*/
     /** @lends XV.CharacteristicPicker# */{
     name: "XV.CharacteristicPicker",
     kind: "XV.PickerWidget",
-    classes: "xv-characteristic-picker",
     collection: "XM.characteristics",
     noneText: "_delete".loc(),
     noneClasses: "xv-negative",
@@ -147,7 +146,7 @@ white:true*/
    */
   enyo.kind(/** @lends XV.CharacteristicItem# */{
     name: "XV.CharacteristicItem",
-    kind: "FittableColumns",
+    kind: "enyo.Control",
     classes: "xv-characteristic-item",
     published: {
       value: null,
@@ -157,13 +156,15 @@ white:true*/
       onValueChange: "controlValueChanged"
     },
     components: [
-      {kind: "XV.CharacteristicPicker", attr: "characteristic",
-        showLabel: false},
-      {kind: "XV.InputWidget", attr: "value", showLabel: false},
-      {kind: "XV.DateWidget", attr: "value", showLabel: false,
-        showing: false},
-      {kind: "XV.OptionsPicker", attr: "value", showLabel: false,
-        showing: false}
+      {controlClasses: 'enyo-inline', components: [
+        {kind: "XV.CharacteristicPicker", attr: "characteristic",
+          showLabel: false},
+        {kind: "XV.InputWidget", attr: "value", showLabel: false},
+        {kind: "XV.DateWidget", attr: "value", showLabel: false,
+          showing: false},
+        {kind: "XV.OptionsPicker", attr: "value", showLabel: false,
+          showing: false}
+      ]}
     ],
     disabledChanged: function (oldValue) {
       this.$.characteristicPicker.setDisabled(this.disabled);
@@ -175,8 +176,8 @@ white:true*/
      @todo Document the controlValueChanged method.
      */
     controlValueChanged: function (inSender, inEvent) {
-      var attr = inSender.getAttr(),
-        value = inSender.getValue(),
+      var attr = inEvent.originator.getAttr(),
+        value = inEvent.originator.getValue(),
         attributes = {},
         model = this.getValue(),
         characteristic,
@@ -266,18 +267,17 @@ white:true*/
       // note: which is now being kept track of in the model, and maybe should
       // only be kept track of in the model.
       which: null,
-      disabled: false
+      disabled: false,
+      showLabel: false,
     },
     components: [
       {kind: "onyx.GroupboxHeader", content: "_characteristics".loc()},
       {kind: "Repeater", count: 0, onSetupItem: "setupItem", components: [
         {kind: "XV.CharacteristicItem"}
       ]},
-      {kind: "FittableColumns", classes: "xv-characteristic-buttons",
-        components: [
+      {controlClasses: 'enyo-inline', classes: "xv-buttons", components: [
         {kind: "onyx.Button", name: "newButton",
-          classes: "icon-plus xv-characteristic-button",
-          onclick: "newItem"}
+          classes: "icon-plus xv-characteristic-button", onclick: "newItem"}
       ]}
     ],
     disabledChanged: function () {
@@ -383,7 +383,7 @@ white:true*/
       this.value.comparator = this.sort;
       this.value.sort();
       this.lengthChanged();
-    }
+    },
   });
 
 }());
index 27418ce..7b4cfed 100644 (file)
@@ -4,52 +4,6 @@ regexp:true, undef:true, trailing:true, white:true */
 
 (function () {
 
-  /**
-    @name XV.Checkbox
-    @class An input control that shows or hides a checkmark when clicked.</br >
-    To implement a checkbox, see {@link XV.CheckboxWidget}.<br />
-    Derived from <a href="http://enyojs.com/api/#onyx.Checkbox">onyx.Checkbox</a>.
-    @extends onyx.Checkbox
-   */
-  enyo.kind(
-    /** @lends XV.Checkbox# */{
-    name: "XV.Checkbox",
-    kind: "onyx.Checkbox",
-    published: {
-      attr: null
-    },
-    events: {
-      onValueChange: ""
-    },
-    handlers: {
-      onchange: "changed"
-    },
-    /**
-    @todo Document the clear method.
-    */
-    clear: function (options) {
-      this.setValue(false, options);
-    },
-    /**
-    @todo Document the setValue method.
-    */
-    setValue: function (value, options) {
-      options = options || {};
-      this._silent = options.silent;
-      this.inherited(arguments);
-      this._silent = false;
-    },
-    /**
-    @todo Document the changed method.
-    */
-    changed: function (inSender, inEvent) {
-      if (!this._silent) {
-        inEvent.value = this.getValue();
-        this.doValueChange(inEvent);
-      }
-    }
-  });
-
   /**
     @name XV.CheckboxWidget
     @class An input control consisting of fittable columns:
@@ -57,19 +11,16 @@ regexp:true, undef:true, trailing:true, white:true */
     Use to implement a styled checkbox
       which is made up of a checkbox input control and its label.
     @extends XV.Input
+    @lends XV.CheckboxWidget
    */
-  enyo.kind(/** @lends XV.CheckboxWidget# */{
+  enyo.kind({
     name: "XV.CheckboxWidget",
-    kind: "XV.Input",
-    classes: "xv-input xv-checkboxwidget",
-    published: {
-      label: ""
-    },
+    kind: "XV.InputWidget",
+    classes: "xv-checkboxwidget",
     components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", components: [
           {name: "input", kind: "onyx.Checkbox", onchange: "inputChanged"}
         ]}
       ]}
@@ -80,32 +31,12 @@ regexp:true, undef:true, trailing:true, white:true */
     clear: function (options) {
       this.setValue(false, options);
     },
-    /**
-    @todo Document the create method.
-    */
-    create: function () {
-      this.inherited(arguments);
-      this.labelChanged();
-    },
-    disabledChanged: function () {
-      this.inherited(arguments);
-      this.$.label.addRemoveClass("disabled", this.getDisabled());
-    },
-    /**
-    @todo Document the inputChanged method.
-    */
+
     inputChanged: function (inSender, inEvent) {
       var input = this.$.input.getValue();
       this.setValue(input);
     },
     /**
-    @todo Document the labelChanged method.
-    */
-    labelChanged: function () {
-      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
-      this.$.label.setContent(label);
-    },
-    /**
     @todo Document the valueChanged method.
     */
     valueChanged: function (value) {
@@ -128,7 +59,7 @@ regexp:true, undef:true, trailing:true, white:true */
    */
   enyo.kind(/** @lends XV.StickyCheckboxWidget# */{
     name: "XV.StickyCheckboxWidget",
-    classes: "xv-input xv-checkboxwidget",
+    kind: "XV.CheckboxWidget",
     published: {
       label: "",
       disabled: false,
@@ -138,10 +69,9 @@ regexp:true, undef:true, trailing:true, white:true */
       onValueChange: ""
     },
     components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", components: [
           {name: "input", kind: "onyx.Checkbox", onchange: "inputChanged"}
         ]}
       ]}
index fc8edae..a20fd81 100644 (file)
@@ -14,14 +14,13 @@ regexp:true, undef:true, trailing:true, white:true, browser:true */
   enyo.kind(
     /** @lends XV.CheckboxWidget# */{
     name: "XV.ComboboxWidget",
-    kind: "XV.Input",
+    kind: "XV.InputWidget",
     published: {
+      attr: null,
       collection: "",
       filter: null,
       disabled: false,
       keyAttribute: "name",
-      label: "",
-      showLabel: true,
       tabStop: true
     },
     classes: "xv-combobox xv-input",
@@ -29,9 +28,9 @@ regexp:true, undef:true, trailing:true, white:true, browser:true */
       onValueChange: "controlValueChanged"
     },
     components: [
-      {kind: "FittableColumns", name: "fittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        {kind: "onyx.InputDecorator", tag: "div", classes: "input-decorator", components: [
+      {controlClasses: 'enyo-inline', name: "container", components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", tag: "div", classes: "xv-icon-decorator", components: [
           {name: "input", kind: "onyx.Input", onkeyup: "keyUp", onkeydown: "keyDown",
             onblur: "receiveBlur", onchange: "inputChanged"},
           {kind: "onyx.IconButton", name: "iconButton", ontap: "toggleCompleter",
@@ -47,8 +46,6 @@ regexp:true, undef:true, trailing:true, white:true, browser:true */
       this.inherited(arguments);
       this.collectionChanged();
       this.filterChanged();
-      this.labelChanged();
-      this.showLabelChanged();
       this.tabStopChanged();
     },
     /**
@@ -117,7 +114,6 @@ regexp:true, undef:true, trailing:true, white:true, browser:true */
     setDisabled: function (isDisabled) {
       this.inherited(arguments);
       this.$.iconButton.setDisabled(isDisabled);
-      this.$.label.addRemoveClass("disabled", isDisabled);
     },
     /**
     @todo Document the keyDown method.
@@ -171,21 +167,11 @@ regexp:true, undef:true, trailing:true, white:true, browser:true */
       return models;
     },
     /**
-    @todo Document the labelChanged method.
-    */
-    labelChanged: function () {
-      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
-      this.$.label.setContent(label);
-    },
-    /**
     @todo Document the receiveBlur method.
     */
     receiveBlur: function (inSender, inEvent) {
       this.autocomplete();
     },
-    showLabelChanged: function () {
-      this.$.label.setShowing(this.getShowLabel());
-    },
     tabStopChanged: function () {
       this.$.input.setAttribute("tabIndex", this.getTabStop() ? null: -1);
     },
index 13f35e7..74ec7c6 100644 (file)
@@ -5,7 +5,7 @@ regexp:true, undef:true, trailing:true, white:true */
 (function () {
 
   /**
-    @name XV.Date
+    @name XV.DateWidget
        @class An input control used to specify a date.<br />
        Reformats and sets a date entered either as a date type or a string.
        If a string is not a recognizable date, sets the input to null.<br />
@@ -13,13 +13,59 @@ regexp:true, undef:true, trailing:true, white:true */
        @extends XV.Input
    */
   enyo.kind(
-    /** @lends XV.Date# */{
-    name: "XV.Date",
-    kind: "XV.Input",
+    /** @lends XV.DateWidget# */{
+    name: "XV.DateWidget",
+    kind: "XV.InputWidget",
+    classes: "xv-input xv-datewidget",
     published: {
+      attr: null,
       nullValue: null,
       nullText: ""
     },
+    components: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", name: "decorator", tag: "div",
+          classes: "xv-icon-decorator", components: [
+          {name: "input", kind: "onyx.Input", onchange: "inputChanged",
+            onkeydown: "keyDown"},
+          {name: "icon", kind: "onyx.Icon", ontap: "iconTapped",
+            classes: "icon-calendar"}
+        ]},
+        {name: "datePickPopup", kind: "onyx.Popup", maxHeight: 400, floating: true,
+            centered: true, modal: true, components: [
+          {kind: "GTS.DatePicker", name: "datePick", style: "min-width:400px;",
+            onChange: "datePicked"}
+        ]}
+      ]}
+    ],
+
+    /**
+     This function handles a date chosen via the
+     datepicker versus text entered into the input field.
+     */
+    datePicked: function (inSender, inEvent) {
+      var date = inEvent, options = {};
+      // mimic the human-typed behavior
+      this.applyTimezoneOffset(date);
+
+      options.silent = true;
+      this.setValue(date, options);
+      this.$.datePickPopup.hide();
+      this.$.input.focus();
+    },
+    disabledChanged: function () {
+      this.inherited(arguments);
+      this.$.label.addRemoveClass("disabled", this.getDisabled());
+    },
+    /**
+      This function handles the click of the calendar icon
+      that opens the datepicker.
+    */
+    iconTapped: function (inSender, inEvent) {
+      this.$.datePickPopup.show();
+      this.$.datePick.render();
+    },
     /**
      Returns the value in the input field of the widget.
      */
@@ -46,7 +92,7 @@ regexp:true, undef:true, trailing:true, white:true */
       } else {
         value = nullValue;
       }
-      XV.Input.prototype.setValue.call(this, value, options);
+      XV.InputWidget.prototype.setValue.call(this, value, options);
     },
     /**
      This function takes the value entered into a DateWidget and returns
@@ -153,107 +199,7 @@ regexp:true, undef:true, trailing:true, white:true */
       } else {
         value = "";
       }
-      return XV.Input.prototype.valueChanged.call(this, value);
-    }
-  });
 
-  /**
-    @name XV.DateWidget
-    @class An input control consisting of fittable columns.<br />
-    Use to implement a styled input field for entering a date
-    including associated popup menu for selecting a date.<br />
-    Creates an HTML input element.
-    @extends XV.Date
-   */
-  enyo.kind(/** @lends XV.DateWidget# */{
-    name: "XV.DateWidget",
-    kind: "XV.Date",
-    classes: "xv-input xv-datewidget",
-    published: {
-      label: "",
-      showLabel: true
-    },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        // setting the tag to "div" on the decorator
-        // so that clicks of button don't get redirected back
-        // to the input field (default behavior)
-        {kind: "onyx.InputDecorator", name: "decorator", tag: "div",
-          classes: "xv-input-decorator", components: [
-          {name: "input", kind: "onyx.Input", onchange: "inputChanged",
-            classes: "xv-subinput", onkeydown: "keyDown"},
-          {name: "icon", kind: "onyx.Icon", ontap: "iconTapped",
-            classes: "icon-calendar"}
-        ]},
-        {name: "datePickPopup", kind: "onyx.Popup", maxHeight: 400, floating: true,
-            centered: true, modal: true, components: [
-          // TODO: get rid of this inline style
-          {kind: "GTS.DatePicker", name: "datePick", style: "min-width:400px;",
-            onChange: "datePicked"}
-        ]}
-      ]}
-    ],
-    /**
-     @todo Document create method.
-     */
-    create: function () {
-      this.inherited(arguments);
-      this.labelChanged();
-      this.showLabelChanged();
-    },
-
-    /**
-     This function handles a date chosen via the
-     datepicker versus text entered into the input field.
-     */
-    datePicked: function (inSender, inEvent) {
-      var date = inEvent, options = {};
-      // mimic the human-typed behavior
-      this.applyTimezoneOffset(date);
-
-      options.silent = true;
-      this.setValue(date, options);
-      this.$.datePickPopup.hide();
-      this.$.input.focus();
-    },
-    disabledChanged: function () {
-      this.inherited(arguments);
-      this.$.label.addRemoveClass("disabled", this.getDisabled());
-    },
-    /**
-      This function handles the click of the calendar icon
-      that opens the datepicker.
-    */
-    iconTapped: function (inSender, inEvent) {
-      this.$.datePickPopup.show();
-      this.$.datePick.render();
-    },
-    /**
-     Sets the label of the Date Widget with text specified in the kind.
-     */
-    labelChanged: function () {
-      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
-      this.$.label.setContent(label);
-    },
-    /**
-     Sets the visibility of the label of the date widget based on
-     the value specified in the kind.
-     */
-    showLabelChanged: function () {
-      if (this.getShowLabel()) {
-        this.$.label.show();
-      } else {
-        this.$.label.hide();
-      }
-    },
-    /**
-     Set the date value into the input field and the date picker and
-     sets the value to the model.
-     */
-    valueChanged: function (value) {
-      var dateValue = value;
-      value = XV.Date.prototype.valueChanged.call(this, value);
       if (!this.$.input.value && this.$.input.attributes.value) {
         // XXX workaround for incident 19171. Something deep into enyo's
         // setters are causing the attributes value to be updated when
@@ -262,8 +208,11 @@ regexp:true, undef:true, trailing:true, white:true */
         // two-step of turning a inputted value into an actual date.
         this.$.input.attributes.value = "";
       }
-      this.$.datePick.setValue(value ? dateValue : new Date());
+
+      this.$.datePick.setValue(value ? value : new Date());
       this.$.datePick.render();
+
+      return XV.InputWidget.prototype.valueChanged.call(this, value);
     }
   });
 
index a67f0e2..d785be8 100644 (file)
@@ -14,7 +14,9 @@ regexp:true, undef:true, trailing:true, white:true */
   enyo.kind(
     /** @lends XV.FileInput# */{
     name: "XV.FileInput",
-    kind: "XV.Input",
+    kind: "XV.InputWidget",
+    showLabel: false,
+    type: "file",
     events: {
       onValueChange: "",
       onNotify: ""
@@ -23,7 +25,8 @@ regexp:true, undef:true, trailing:true, white:true */
       onValueChange: "valueChange"
     },
     components: [
-      {name: "input", tag: "input type=file", kind: "onyx.Input",  classes: "xv-subinput", onchange: "inputChanged"},
+      {name: "label", fit: true, classes: "xv-label"},
+      {name: "input", kind: "onyx.Input", onchange: "inputChanged"},
       {name: "scrim", kind: "onyx.Scrim", showing: false, floating: true}
     ],
 
index c388028..9641d60 100644 (file)
@@ -5,7 +5,7 @@ regexp:true, undef:true, trailing:true, white:true */
 (function () {
 
   /**
-    @name XV.Input
+    @name XV.InputWidget
     @class Maintains a consistent API to be used by workspaces.<br />
     The superkind from which other xTuple input objects are derived.<br />
     To create an input field for strings, see {@link XV.InputWidget}.<br />
@@ -17,15 +17,18 @@ regexp:true, undef:true, trailing:true, white:true */
     To create a togglebutton, see {@link XV.TogglebuttonWidget}.<br />
    */
   enyo.kind(
-    /** @lends XV.Input# */{
-    name: "XV.Input",
+    /** @lends XV.InputWidget# */{
+    name: "XV.InputWidget",
+    classes: "xv-input",
     published: {
       attr: null,
       value: null,
       disabled: false,
       placeholder: null,
       type: null,
-      maxlength: null
+      maxlength: null,
+      label: "",
+      showLabel: true
     },
     events: {
       "onValueChange": ""
@@ -34,32 +37,37 @@ regexp:true, undef:true, trailing:true, white:true */
       onblur: "receiveBlur"
     },
     components: [
-      {name: "input", kind: "onyx.Input", classes: "xv-subinput", onchange: "inputChanged", onkeydown: "keyDown"}
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", components: [
+          {name: "input", kind: "onyx.Input", onchange: "inputChanged", onkeydown: "keyDown"}
+        ]}
+      ]}
     ],
-    /**
-      Sets the value of the input to an empty string
-    */
-    clear: function (options) {
-      this.setValue("", options);
-    },
-    /**
-    @todo Document the create method.
-    */
     create: function () {
       this.inherited(arguments);
       this.placeholderChanged();
       this.disabledChanged();
       this.typeChanged();
       this.maxlengthChanged();
+      this.labelChanged();
+      this.showLabelChanged();
+    },
+    /**
+      Sets the value of the input to an empty string
+    */
+    clear: function (options) {
+      this.setValue("", options);
     },
     /**
      The disabledChanged method, and many below it, are here to deal with
-     the fact that XV.Input doesvnot inherit from onyx.input or enyo.input,
+     the fact that XV.Input does not inherit from onyx.input or enyo.input,
      and so insofar as it needs to support their APIs, we
      have to redeclare the methods and pass through the data.
     */
     disabledChanged: function () {
       this.$.input.setDisabled(this.getDisabled());
+      this.$.label.addRemoveClass("disabled", this.getDisabled());
     },
     focus: function () {
       this.$.input.focus();
@@ -100,11 +108,12 @@ regexp:true, undef:true, trailing:true, white:true */
       }
     },
     /**
-    @todo Document the placeholderChanged method.
+      Sets the placeholder on the input field.
     */
     placeholderChanged: function () {
-      var placeholder = this.getPlaceholder();
-      this.$.input.setPlaceholder(placeholder);
+      if (_.isFunction(this.$.input.setPlaceholder)) {
+        this.$.input.setPlaceholder(this.placeholder);
+      }
     },
     /**
       Webkit browsers do not always emit the proper change event,
@@ -153,65 +162,17 @@ regexp:true, undef:true, trailing:true, white:true */
       return value;
     },
     /**
-      Pass through attributes intended for onyx input inside.
-    */
-    setInputStyle: function (style) {
-      this.$.input.setStyle(style);
-    },
-    /**
-      Pass through attributes intended for onyx input inside.
+      Sets the type attribute for input field.
     */
     typeChanged: function () {
       this.$.input.setType(this.getType());
     },
 
-    maxlengthChanged: function () {
-      this.$.input.setAttribute("maxlength", this.maxlength);
-    }
-  });
-
-  /**
-    @name XV.InputWidget
-    @class An input control consisting of fittable columns:
-      a styled label and an onyx.Input placed inside an onyx.InputDecorator,
-      which provides styling.<br />
-    Any controls in the InputDecorator appear to be inside an area styled as an input.<br />
-    Use to implement a styled input field for strings.<br />
-    Creates an HTML input element.
-    @extends XV.Input
-   */
-  enyo.kind(/** @lends XV.InputWidget# */{
-    name: "XV.InputWidget",
-    kind: "XV.Input",
-    classes: "xv-input",
-    published: {
-      label: "",
-      showLabel: true
-    },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
-          {name: "input", kind: "onyx.Input", classes: "xv-subinput",
-            onchange: "inputChanged", onkeydown: "keyDown"}
-        ]}
-      ]}
-    ],
     /**
-    @todo Document the create method.
+      Set the maxlength attribute on the input field.
     */
-    create: function () {
-      this.inherited(arguments);
-      this.labelChanged();
-      this.placeholderChanged();
-      this.showLabelChanged();
-    },
-
-    disabledChanged: function () {
-      this.inherited(arguments);
-      var disabled = this.getDisabled();
-      this.$.label.addRemoveClass("disabled", disabled);
+    maxlengthChanged: function () {
+      this.$.input.setAttribute("maxlength", this.maxlength);
     },
 
     /**
@@ -223,14 +184,11 @@ regexp:true, undef:true, trailing:true, white:true */
     },
 
     /**
-    @todo Document the showLabelChanged method.
+      Sets visibility of the widget label.
     */
     showLabelChanged: function () {
-      if (this.getShowLabel()) {
-        this.$.label.show();
-      } else {
-        this.$.label.hide();
-      }
+      this.$.label.setShowing(this.getShowLabel());
     }
   });
+
 }());
index 37e00be..4966429 100644 (file)
@@ -12,11 +12,15 @@ regexp:true, undef:true, trailing:true, white:true */
    */
   enyo.kind(
     /** @lends XV.Number# */{
-    name: "XV.Number",
-    kind: "XV.Input",
+    name: "XV.NumberWidget",
+    kind: "XV.InputWidget",
+    classes: "xv-numberwidget xv-input",
     published: {
+      attr: null,
       scale: 0,
-      formatting: true
+      formatting: true,
+      label: "",
+      showLabel: true
     },
     /**
     @todo Document the setValue method.
@@ -25,7 +29,7 @@ regexp:true, undef:true, trailing:true, white:true */
       // use isNaN here because this value could be a number String, 0 value, or null
       // only want to set value as null in cases of bad strings and null/undefined
       value = value !== null && !isNaN(value) ? XT.math.round(value, this.getScale()) : null;
-      XV.Input.prototype.setValue.call(this, value, options);
+      this.inherited(arguments);
     },
     /**
       Determines whether the user input is numeric.
@@ -56,63 +60,7 @@ regexp:true, undef:true, trailing:true, white:true */
       } else {
         value = "";
       }
-      return XV.Input.prototype.valueChanged.call(this, value);
-    }
-  });
-
-  /**
-    @name XV.NumberWidget
-    @class An input control consisting of fittable columns: label, decorator, and input field.<br />
-    Use to implement an input field for strings that represents a number, such as prices.  This widget
-    includes a style to right-justify the text entered into the input field.
-    @extends XV.Number
-   */
-  enyo.kind(/** @lends XV.NumberWidget# */{
-    name: "XV.NumberWidget",
-    kind: "XV.Number",
-    classes: "xv-numberwidget xv-input",
-    published: {
-      label: "",
-      showLabel: true,
-      placeholder: ""
-    },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
-          {name: "input", kind: "onyx.Input", onchange: "inputChanged", onkeydown: "keyDown", type: "number"}
-        ]}
-      ]}
-    ],
-    /**
-     @todo Document the create method.
-     */
-    create: function () {
       this.inherited(arguments);
-      this.labelChanged();
-      this.showLabelChanged();
-    },
-    disabledChanged: function () {
-      this.inherited(arguments);
-      this.$.label.addRemoveClass("disabled", this.getDisabled());
-    },
-    /**
-     @todo Document the labelChanged method.
-     */
-    labelChanged: function () {
-      var label = (this.getLabel() || ("_" + this.attr + "").loc()) + ":";
-      this.$.label.setContent(label);
-    },
-    /**
-     @todo Document the showLabelChanged method.
-     */
-    showLabelChanged: function () {
-      if (this.getShowLabel()) {
-        this.$.label.show();
-      } else {
-        this.$.label.hide();
-      }
     }
   });
 
index f1a88df..c5af7e0 100644 (file)
@@ -19,28 +19,23 @@ regexp:true, undef:true, trailing:true, white:true */
       showSlider: false,
       maxValue: 100,
       label: "",
-      showLabel: true
+      showLabel: true,
+      type: "text"
     },
-    classes: "spinner",
+    classes: "xv-spinnerwidget",
     components: [
-      {kind: "FittableColumns", components: [
-        {kind: "FittableRows", components: [
-          {name: "label", classes: "xv-label"}
-        ]},
-        {kind: "FittableRows", fit: true, components: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {controlClasses: 'enyo-inline', components: [
           {kind: "onyx.Slider", name: "slider", onChange: "sliderChanged", classes: "slider"},
-          {kind: "onyx.InputDecorator", tag: "div", classes: "input-decorator", components: [
-            {name: "input", kind: "onyx.Input", classes: "xv-subinput",
+          {kind: "onyx.InputDecorator", tag: "div", classes: "xv-icon-decorator", components: [
+            {name: "input", kind: "onyx.Input",
               onchange: "inputChanged", onkeydown: "keyDown"},
-            {kind: "FittableRows", components: [
-              {kind: "onyx.Button", classes: "buttons", ontap: "increase",
-                attributes: {tabIndex: "-1"}, components: [
-                {tag: "i", classes: "icon-angle-up"}
-              ]},
-              {kind: "onyx.Button", classes: "buttons", ontap: "decrease",
-                attributes: {tabIndex: "-1"}, components: [
-                {tag: "i", classes: "icon-angle-down"}
-              ]}
+            {components: [
+              {kind: "onyx.IconButton", ontap: "increase",
+                attributes: {tabIndex: "-1"}, classes: "icon-angle-up"},
+              {kind: "onyx.IconButton", ontap: "decrease",
+                attributes: {tabIndex: "-1"}, classes: "icon-angle-down"}
             ]}
           ]}
         ]}
@@ -48,9 +43,7 @@ regexp:true, undef:true, trailing:true, white:true */
     ],
     create: function () {
       this.inherited(arguments);
-      this.labelChanged();
       this.showSliderChanged();
-      this.showLabelChanged();
     },
     /**
       Decreases the value of the input field by an increment of
index 720976d..5efc2e0 100644 (file)
@@ -31,7 +31,7 @@ white:true*/
       onValueChange: "parameterChanged"
     },
     components: [
-      {name: "input", classes: "xv-parameter-item-input"}
+      {name: "input"}
     ],
     defaultKind: "XV.InputWidget",
     /**
@@ -42,7 +42,7 @@ white:true*/
       this.labelChanged();
       if (!this.getOperator() && this.defaultKind === "XV.InputWidget") {
         this.setOperator("MATCHES");
-      } else if (this.$.input instanceof XV.Picker) {
+      } else if (this.$.input instanceof XV.PickerWidget) {
         this.$.input.setNoneText("_any".loc());
       }
     },
index 05944d2..0473cd3 100644 (file)
@@ -19,9 +19,9 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
    */
   enyo.kind(
     /** @lends XV.PickerWidget# */{
-    name: "XV.Picker",
+    name: "XV.PickerWidget",
     kind: "enyo.Control",
-    classes: "xv-input",
+    classes: "xv-pickerwidget",
     events: /** @lends XV.PickerWidget# */{
       /**
         @property {Object} inEvent The payload that's attached to bubbled-up events
@@ -41,16 +41,22 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       noneClasses: "",
       showNone: true,
       prerender: true,
-      defaultValue: null
+      defaultValue: null,
+      showLabel: true,
+      label: ""
     },
     handlers: {
       onSelect: "itemSelected"
     },
     components: [
-      {kind: "onyx.PickerDecorator",
-        components: [
-        {kind: "XV.PickerButton", name: "pickerButton", content: "_none".loc(), onkeyup: "keyUp"},
-        {name: "picker", kind: "onyx.Picker"}
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", name: "inputWrapper", components: [
+          {kind: "onyx.PickerDecorator", components: [
+            {kind: "XV.PickerButton", name: "pickerButton", content: "_none".loc(), onkeyup: "keyUp"},
+            {name: "picker", kind: "onyx.Picker"}
+          ]}
+        ]}
       ]}
     ],
     /**
@@ -155,6 +161,9 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       if (defaultValue) {
         this.setValue(defaultValue, {silent: true});
       }
+
+      this.labelChanged();
+      this.showLabelChanged();
     },
     destroy: function () {
       if (this._collection && this._collection.off) {
@@ -401,44 +410,6 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
           }
         }
       }
-    }
-  });
-
-  /**
-    @name XV.PickerWidget
-    @class A picker control that implements a dropdown list of items which can be selected.<br />
-    Unlike the {@link XV.RelationWidget}, the collection is stored local to the widget.<br />
-    The superkind of {@link XV.CharacteristicPicker}.<br />
-    Derived from <a href="http://enyojs.com/api/#enyo.Control">enyo.Control</a>.
-    @extends enyo.Control
-   */
-  enyo.kind(/** @lends XV.PickerWidget# */{
-    name: "XV.PickerWidget",
-    kind: "XV.Picker",
-    published: {
-      label: "",
-      showLabel: true
-    },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", name: "inputWrapper", classes: "xv-input-decorator",
-          components: [
-          {kind: "onyx.PickerDecorator",
-            components: [
-            {kind: "XV.PickerButton", name: "pickerButton", content: "_none".loc(), onkeyup: "keyUp"},
-            {name: "picker", kind: "onyx.Picker"}
-          ]}
-        ]}
-      ]}
-    ],
-    /**
-     @todo Document the create method.
-     */
-    create: function () {
-      this.inherited(arguments);
-      this.labelChanged();
-      this.showLabelChanged();
     },
     /**
      @todo Document the labelChanged method.
index 455bd44..3783b06 100644 (file)
@@ -14,7 +14,8 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
   enyo.kind(
     /** @lends XV.RelationWidget# */{
     name: "XV.RelationWidget",
-    kind: enyo.Control,
+    // TODO: needs to inherit from InputWidget
+    kind: "enyo.Control",
     classes: "xv-input xv-relationwidget",
     published: {
       attr: null,
@@ -22,7 +23,7 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       placeholder: "",
       value: null,
       list: "",
-      collection: "",
+      collection: null,
       disabled: false,
       /**
         This can be a string or an array. If an array, all attributes
@@ -48,31 +49,30 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       onSelect: "itemSelected"
     },
     components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
-        // TODO: Put the InputDecorator and description in a FittableRows
-        {kind: "onyx.InputDecorator", name: "decorator",
-          classes: "xv-input-decorator", components: [
-          {name: 'input', kind: "onyx.Input", classes: "xv-subinput",
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", name: "decorator", classes: "xv-icon-decorator", components: [
+          {name: "input", kind: "onyx.Input",
             onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
-            onfocus: "receiveFocus", fit: true
-          },
+            onfocus: "receiveFocus"},
           {kind: "onyx.MenuDecorator", components: [
             {kind: "onyx.IconButton", classes: "icon-folder-open-alt"},
-            {name: 'popupMenu', floating: true, kind: "onyx.Menu",
-              components: [
-              {kind: "XV.MenuItem", name: 'searchItem', content: "_search".loc()},
-              {kind: "XV.MenuItem", name: 'openItem', content: "_open".loc(),
-                disabled: true},
-              {kind: "XV.MenuItem", name: 'newItem', content: "_new".loc(),
-                disabled: true}
+            {kind: "onyx.Menu", name: 'popupMenu', floating: true, components: [
+              {kind: "XV.MenuItem", name: "searchItem", content: "_search".loc()},
+              {kind: "XV.MenuItem", name: "openItem", content: "_open".loc(), disabled: true},
+              {kind: "XV.MenuItem", name: "newItem", content: "_new".loc(), disabled: true}
             ]}
           ]},
           {name: "completer", kind: "XV.Completer"}
         ]}
       ]},
-      {name: "name", classes: "xv-relationwidget-description"},
-      {name: "description", classes: "xv-relationwidget-description xv-relationwidget-secondarydescription"}
+      {name: 'descriptionContainer', classes: 'xv-invisible-wrapper'}
+    ],
+    descriptionComponents: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "name", classes: "xv-description"},
+        {name: "description", classes: "xv-description"}
+      ]}
     ],
     /**
       Add a parameter to the query object on the widget. Parameter conventions should
@@ -144,6 +144,11 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       this.listChanged();
       this.labelChanged();
       this.disabledChanged();
+
+      // create description components
+      _.each(this.descriptionComponents, function (component) {
+        this.$.descriptionContainer.createComponent(component, {owner: this});
+      }, this);
     },
     /**
      @todo Document the disabledChanged method.
@@ -153,9 +158,12 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
       this.$.input.setDisabled(disabled);
       this.$.searchItem.setDisabled(disabled);
       this.$.newItem.setDisabled(_couldNotCreate.apply(this) || disabled);
-      this.$.name.addRemoveClass("disabled", disabled);
-      this.$.description.addRemoveClass("disabled", disabled);
       this.$.label.addRemoveClass("disabled", disabled);
+
+      // _.each(this.$.descriptionContainer.$, function (component) {
+      //   component.addRemoveClass("disabled", disabled);
+      // }, this);
+      this.$.descriptionContainer.addRemoveClass('disabled', disabled);
     },
     /**
       Query the database.
@@ -540,12 +548,11 @@ regexp:true, undef:true, trailing:true, white:true, strict:false */
         additionalValue = value.getValue(additional) || "";
       }
       this.$.input.setValue(keyValue);
+
       this.$.name.setShowing(nameValue);
       this.$.name.setContent(nameValue);
       this.$.description.setShowing(descripValue);
       this.$.description.setContent(descripValue);
-      //this.$.additionalInfo.setShowing(additionalValue);
-      //this.$.additionalInfo.setContent(additionalValue);
 
       // Only notify if selection actually changed
       if (newId !== oldId && !options.silent) { this.doValueChange(inEvent); }
index e4d25dd..6b664c7 100644 (file)
@@ -11,17 +11,18 @@ regexp:true, undef:true, trailing:true, white:true */
     Creates an HTML textarea element.<br />
     For example, used as a component of {@link XV.CommentBoxItem}.
     @extends XV.Input
-   */
+  */
   enyo.kind(
     /** @lends XV.TextArea# */{
     name: "XV.TextArea",
-    kind: "XV.Input",
+    kind: "XV.InputWidget",
     classes: "xv-textarea",
     published: {
       attr: null,
-      placeholder: ""
+      showLabel: false
     },
     components: [
+      {name: "label", classes: "xv-label"},
       {name: "input", kind: "onyx.TextArea", classes: "xv-textarea-input",
         onchange: "inputChanged", onkeydown: "keyDown"}
     ]
index e094c27..230b90e 100644 (file)
@@ -5,30 +5,32 @@ regexp:true, undef:true, trailing:true, white:true */
 (function () {
 
   /**
-    @name XV.ToggleButton
-    @class A control that looks like a switch with labels for two states.<br />
-    Derived from <a href="http://enyojs.com/api/#onyx.ToggleButton">onyx.ToggleButton</a>.
-    @extends onyx.ToggleButton
+    @name XV.ToggleButtonWidget
+    @class An input control consisting of fittable columns:
+     label, decorator, and toggle button.<br />
+    Use to implement a toggle button, a switch with labels for two states.<br />
+    Creates an HTML input element.
+    @extends XV.Input
    */
-  enyo.kind(
-    /** @lends XV.ToggleButton# */{
-    name: "XV.ToggleButton",
-    kind: "onyx.ToggleButton",
-    published: {
-      attr: null
-    },
+  enyo.kind({
+    name: "XV.ToggleButtonWidget",
+    kind: "XV.InputWidget",
+    classes: "xv-inputwidget xv-checkboxwidget",
     events: {
       onValueChange: ""
     },
     handlers: {
       onChange: "changed"
     },
-    /**
-     @todo Document the clear method.
-     */
-    clear: function (options) {
-      this.setValue(false, options);
-    },
+    components: [
+      {controlClasses: 'enyo-inline', components: [
+        {name: "label", content: "", classes: "xv-label"},
+        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
+          components: [
+          {name: "input", kind: "onyx.ToggleButton", onChange: "inputChanged"}
+        ]}
+      ]}
+    ],
     /**
      @todo Document the setValue method.
      */
@@ -46,33 +48,7 @@ regexp:true, undef:true, trailing:true, white:true */
         inEvent.value = this.getValue();
         this.doValueChange(inEvent);
       }
-    }
-  });
-
-  /**
-    @name XV.ToggleButtonWidget
-    @class An input control consisting of fittable columns:
-     label, decorator, and toggle button.<br />
-    Use to implement a toggle button, a switch with labels for two states.<br />
-    Creates an HTML input element.
-    @extends XV.Input
-   */
-  enyo.kind(/** @lends XV.ToggleButtonWidget# */{
-    name: "XV.ToggleButtonWidget",
-    kind: "XV.Input",
-    classes: "xv-inputwidget xv-checkboxwidget",
-    published: {
-      label: ""
     },
-    components: [
-      {kind: "FittableColumns", components: [
-        {name: "label", content: "", classes: "xv-label"},
-        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
-          components: [
-          {name: "input", kind: "onyx.ToggleButton", onChange: "inputChanged"}
-        ]}
-      ]}
-    ],
     /**
      @todo Document the clear method.
      */
@@ -89,10 +65,6 @@ regexp:true, undef:true, trailing:true, white:true */
       var options = {silent: true};
       this.valueChanged(this.getValue(), options);
     },
-    disabledChanged: function () {
-      this.inherited(arguments);
-      this.$.label.addRemoveClass("disabled", this.getDisabled());
-    },
     /**
      @todo Document the inputChanged method.
      */
@@ -100,20 +72,6 @@ regexp:true, undef:true, trailing:true, white:true */
       var input = this.$.input.getValue();
       this.setValue(input);
     },
-    /**
-     @todo Document the labelChanged method.
-     */
-    labelChanged: function () {
-      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
-      this.$.label.setContent(label);
-    },
-    /**
-      Not applicable in the context of a toggle button,
-      even though it is available to input widgets generally.
-     */
-    placeholderChanged: function () {
-      // Not applicable
-    },
     /**
      @todo Document the valueChanged method.
      */
diff --git a/lib/orm/LICENSE.txt b/lib/orm/LICENSE.txt
deleted file mode 100644 (file)
index c4be0f3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-This software uses the The PostgreSQL License
-
-Copyright (c) 2014, OpenMFG, LLC, d/b/a XTUPLE
-
-Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies.
-
-IN NO EVENT SHALL XTUPLE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF XTUPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-XTUPLE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND XTUPLE HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
index 2d71da0..419d819 100644 (file)
@@ -1,9 +1 @@
-do $$
-  /* Only create the schema if it hasn't been created already */
-  var res, sql = "select schema_name from information_schema.schemata where schema_name = 'sys'",
-  res = plv8.execute(sql);
-  if (!res.length) {
-    sql = "create schema sys; grant all on schema sys to group xtrole;"
-    plv8.execute(sql);
-  }
-$$ language plv8;
+select xt.create_schema('sys');
index 4f21c27..933c25a 100644 (file)
@@ -1,9 +1 @@
-do $$
-  /* Only create the schema if it hasn't been created already */
-  var res, sql = "select schema_name from information_schema.schemata where schema_name = 'xm'",
-  res = plv8.execute(sql);
-  if (!res.length) {
-    sql = "create schema xm; grant all on schema xm to group xtrole;"
-    plv8.execute(sql);
-  }
-$$ language plv8;
\ No newline at end of file
+select xt.create_schema('xm');
index 025466b..45ce9ec 100644 (file)
@@ -3,8 +3,9 @@
   "version": "1.3.9",
   "databaseScripts": [
     "create_plv8.sql",
-    "create_xm_schema.sql",
+    "xt/functions/create_schema.sql",
     "create_sys_schema.sql",
+    "create_xm_schema.sql",
     "xt/functions/add_inheritance.sql",
     "xt/functions/any_numeric.sql",
     "xt/functions/any_text.sql",
diff --git a/lib/orm/source/xt/functions/add_comment_type.sql b/lib/orm/source/xt/functions/add_comment_type.sql
new file mode 100644 (file)
index 0000000..5eb067a
--- /dev/null
@@ -0,0 +1,32 @@
+drop function if exists xt.add_comment_type(text, text, text);
+
+create or replace function xt.add_comment_type(text, text, text) returns boolean volatile as $$
+DECLARE
+   _module  ALIAS FOR $1;
+   _comment ALIAS FOR $2;
+   _descr   ALIAS FOR $3;
+   _cmntid INTEGER;
+
+BEGIN
+  SELECT source_id INTO _cmntid
+       FROM source WHERE source_name = _comment;
+
+  IF (NOT FOUND) THEN
+    INSERT INTO source (source_module, source_name, source_descrip)
+      VALUES (_module, _comment, _descr) 
+      RETURNING source_id INTO _cmntid;
+
+  INSERT INTO cmnttypesource (cmnttypesource_cmnttype_id, cmnttypesource_source_id)
+       VALUES (1, _cmntid);  -- General Comments
+  INSERT INTO cmnttypesource (cmnttypesource_cmnttype_id, cmnttypesource_source_id)
+         VALUES (2, _cmntid);  -- ChangeLog Comments
+  
+  END IF;
+
+  RETURN true;
+
+END;
+
+$$ language 'plpgsql';
+
+
diff --git a/lib/orm/source/xt/functions/create_schema.sql b/lib/orm/source/xt/functions/create_schema.sql
new file mode 100644 (file)
index 0000000..9134819
--- /dev/null
@@ -0,0 +1,25 @@
+create or replace function xt.create_schema(sch text) returns boolean volatile as $$
+declare
+  count integer;
+  query text;
+begin
+
+  /* Only create the schema if it hasn't been created already */
+  perform *
+  from information_schema.schemata
+  where schema_name = sch;
+
+  get diagnostics count = row_count;
+
+  if (count > 0) then
+    return false;
+  end if;
+
+  query = 'create schema ' || sch || ';' ||
+           'grant all on schema ' || sch || ' to group xtrole;';
+  execute query;
+
+  return true;
+
+end;
+$$ language 'plpgsql';
index a9b6694..0943f00 100644 (file)
@@ -77,6 +77,11 @@ select xt.install_js('XT','Discovery','xtuple', $$
       master.description = "Lets you get and manipulate all xTuple ERP business objects.";
       master.discoveryRestUrl = rootUrl + org + "/discovery/" + version + "/apis/" + version + "/rest";
       master.discoveryLink = "./apis/" + version + "/rest";
+      master.parameters = {
+        "resources": "object",
+        "description": "A query parameter array of resources you want to return. Useful for requesting a subset of resources instead of all of them. e.g. ?resources[]=Contact&resources[]=ToDo",
+        "location": "query"
+      };
       master.icons = {
         "x16": rootUrl + org + "/assets/api/api-16.png",
         "x32": rootUrl + org + "/assets/api/api-32.png"
@@ -586,8 +591,8 @@ select xt.install_js('XT','Discovery','xtuple', $$
           "query": {
             "type": "object",
             "description": "Query different resource properties based on their JSON-Schema. e.g. ?query[property1][BEGINS_WITH]=foo&query[property2][EQUALS]=bar",
-            "location": "query",
-            "$ref": "TODO: add this when moving to JSON-Schema draft v5"
+            "location": "query"
+            //"$ref": "TODO: add this when moving to JSON-Schema draft v5"
           },
           "orderby": {
             "type": "object",
@@ -651,8 +656,8 @@ select xt.install_js('XT','Discovery','xtuple', $$
           "query": {
             "type": "object",
             "description": "Query different resource properties based on their JSON-Schema. e.g. ?query[property1][BEGINS_WITH]=foo&query[property2][EQUALS]=bar",
-            "location": "query",
-            "$ref": "TODO"
+            "location": "query"
+            //"$ref": "TODO"
           },
           "orderby": {
             "type": "object",
@@ -790,6 +795,8 @@ select xt.install_js('XT','Discovery','xtuple', $$
         if (typeof method === 'function' && method.description && method.schema) {
           for (var schema in method.schema) {
             schemas[schema] = method.schema[schema];
+            schemas[schema].id = schema;
+            schemas[schema].type = 'object';
           }
         }
       }
index debd3c6..5115c1d 100644 (file)
@@ -289,7 +289,7 @@ select xt.install_js('XT','Schema','xtuple', $$
         nkey = XT.Orm.naturalKey(orm),
         pkey = XT.Orm.primaryKey(orm),
         prop,
-        ret = {},
+        ret = {"id": orm.type, "type": "object"},
         relatedORM = {},
         relatedKey,
         relatedKeyProp,
index 83ac49a..b9d95c5 100644 (file)
@@ -1,11 +1,13 @@
-/*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
+/*jshint node:true, indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
 newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true,
 white:true*/
-/*global SYS:true, XM:true, Backbone:true, _:true */
+/*global SYS:true, XM:true, Backbone:true, _:true, X: true */
 
 (function () {
   "use strict";
 
+  var async = require("async");
+
   /**
     @class
 
@@ -106,8 +108,55 @@ white:true*/
   SYS.User = XM.SimpleModel.extend({
     /** @scope SYS.User.prototype */
 
-    recordType: 'SYS.User'
-
+    recordType: 'SYS.User',
+
+    /**
+      Checks for a user privilege. Also checks all the roles that the user is a part of.
+      Necessarily async because not all the relevant data is nested.
+      Not portable to the client because of the backbone-relational-lessness
+      of the models.
+      `callback(err, result)` where result is truthy iff the user has the privilege
+    */
+    checkPrivilege: function (privName, database, callback) {
+      var privCheck = _.find(this.get("grantedPrivileges"), function (model) {
+        return model.privilege === privName;
+      });
+      if (privCheck) {
+        callback(); // the user has this privilege!
+        return;
+      }
+      // this gets a little dicey: check all the user's roles for the priv, which
+      // requires async.map
+      var roles = _.map(this.get("grantedUserAccountRoles"), function (grantedRole) {
+        return grantedRole.userAccountRole;
+      });
+      var checkRole = function (roleName, next) {
+        var role = new SYS.UserAccountRole();
+        role.fetch({
+          id: roleName,
+          username: X.options.databaseServer.user,
+          database: database,
+          success: function (roleModel, results) {
+            var rolePriv = _.find(roleModel.get("grantedPrivileges"), function (grantedPriv) {
+              return grantedPriv.privilege === privName;
+            });
+            next(null, rolePriv);
+          }
+        });
+      };
+      async.map(roles, checkRole, function (err, results) {
+        // if any of the roles give the priv, then the user has the priv
+        var result = _.reduce(results, function (memo, priv) {
+          return priv || memo;
+        }, false);
+        console.log(result);
+        if (err || !result) {
+          callback({message: "_insufficientPrivileges"});
+          return;
+        }
+        callback(); // success!
+      });
+    }
   });
 
   /**
index 6750a1a..f2b9145 100755 (executable)
@@ -10,6 +10,7 @@ _ = require("underscore");
 jsonpatch = require("json-patch");
 SYS = {};
 XT = { };
+var express = require('express');
 var app;
 
 (function () {
@@ -94,46 +95,38 @@ var app;
   XT.session = Object.create(XT.Session);
   XT.session.schemas.SYS = false;
 
-
-//
-// Load all extension-defined routes. By convention the paths,
-// filenames, and functions to be used
-// for the routes should be described in a file called routes.js
-// in the routes directory.
-//
-/*
-if (X.options.extensionRoutes && X.options.extensionRoutes.length > 0) {
-  _.each(X.options.extensionRoutes, function (route) {
-    "use strict";
-    var routes = require(__dirname + "/" + route + "/routes");
-
-    _.each(routes, function (routeDetails) {
-      var verb = (routeDetails.verb || "all").toLowerCase();
-      if (_.contains(["all", "get", "post", "patch", "delete"], verb)) {
-        app[verb]('/:org/' + routeDetails.path, routeDetails.function);
-      } else {
-        console.log("Invalid verb for extension-defined route " + routeDetails.path);
-      }
+  var getExtensionDir = function (extension) {
+    var dirMap = {
+      "/private-extensions": X.path.join(__dirname, "../..", extension.location, "source", extension.name),
+      "/xtuple-extensions": X.path.join(__dirname, "../..", extension.location, "source", extension.name),
+      "/core-extensions": X.path.join(__dirname, "../enyo-client/extensions/source", extension.name),
+      "npm": X.path.join(__dirname, "../node_modules", extension.name)
+    };
+    return dirMap[extension.location];
+  };
+  var useClientDir = X.useClientDir = function (path, dir) {
+    path = path.indexOf("npm") === 0 ? "/" + path : path;
+    _.each(X.options.datasource.databases, function (orgValue, orgKey, orgList) {
+      app.use("/" + orgValue + path, express.static(dir, { maxAge: 86400000 }));
     });
-  });
-}
-*/
-
-  var loadExtensionRoutes = function (extension) {
-    if (!_.contains(["/private-extensions", "/xtuple-extensions"], extension.location)) {
-      return;
-    }
-    if (!app) {
-      // XXX time bomb: assuming app has been initialized, below, by now
-      XT.log("Could not load extension routes");
-      return;
-    }
-    var manifest = JSON.parse(X.fs.readFileSync(X.path.join(__dirname, "../..", extension.location, "source",
-        extension.name, "database/source/manifest.js")));
+  };
+  var loadExtensionClientside = function (extension) {
+    var extensionLocation = extension.location === "npm" ? extension.location : extension.location + "/source";
+    useClientDir(extensionLocation + "/" + extension.name + "/client", X.path.join(getExtensionDir(extension), "client"));
+  };
+  var loadExtensionServerside = function (extension) {
+    var packagePath = X.path.join(getExtensionDir(extension), "package.json");
+    var packageJson = X.fs.existsSync(packagePath) ? require(packagePath) : undefined;
+    var manifestPath = X.path.join(getExtensionDir(extension), "database/source/manifest.js");
+    var manifest = X.fs.existsSync(manifestPath) ? JSON.parse(X.fs.readFileSync(manifestPath)) : {};
+    var version = packageJson ? packageJson.version : manifest.version;
+    X.versions[extension.name] = version || "none"; // XXX the "none" is temporary until we have core extensions in npm
+
+    // TODO: be able to define routes in package.json
     _.each(manifest.routes || [], function (routeDetails) {
       var verb = (routeDetails.verb || "all").toLowerCase(),
-        func = require(X.path.join(__dirname, "../..", extension.location, "source",
-          extension.name, "node-datasource", routeDetails.filename))[routeDetails.functionName];
+        func = require(X.path.join(getExtensionDir(extension),
+          "node-datasource", routeDetails.filename))[routeDetails.functionName];
 
       if (_.contains(["all", "get", "post", "patch", "delete"], verb)) {
         app[verb]('/:org/' + routeDetails.path, func);
@@ -155,7 +148,15 @@ if (X.options.extensionRoutes && X.options.extensionRoutes.length > 0) {
     extensions.fetch({
       database: X.options.datasource.databases[0],
       success: function (coll, results, options) {
-        _.each(results, loadExtensionRoutes);
+        if (!app) {
+          // XXX time bomb: assuming app has been initialized, below, by now
+          XT.log("Could not load extension routes or client-side code because the app has not started");
+          process.exit(1);
+          return;
+        }
+        useClientDir("/client", "../enyo-client/application");
+        _.each(results, loadExtensionServerside);
+        _.each(results, loadExtensionClientside);
       }
     });
   };
@@ -173,24 +174,21 @@ if (X.options.extensionRoutes && X.options.extensionRoutes.length > 0) {
  */
 
 var packageJson = X.fs.readFileSync("../package.json");
-try {
-  X.version = JSON.parse(packageJson).version;
-} catch (error) {
-
-}
+X.versions = {
+  core: JSON.parse(packageJson).version
+};
 
 /**
  * Module dependencies.
  */
-var express = require('express'),
-    passport = require('passport'),
-    oauth2 = require('./oauth2/oauth2'),
-    routes = require('./routes/routes'),
-    socketio = require('socket.io'),
-    url = require('url'),
-    utils = require('./oauth2/utils'),
-    user = require('./oauth2/user'),
-    destroySession;
+var passport = require('passport'),
+  oauth2 = require('./oauth2/oauth2'),
+  routes = require('./routes/routes'),
+  socketio = require('socket.io'),
+  url = require('url'),
+  utils = require('./oauth2/utils'),
+  user = require('./oauth2/user'),
+  destroySession;
 
 // TODO - for testing. remove...
 //http://stackoverflow.com/questions/13091037/node-js-heap-snapshots-and-google-chrome-snapshot-viewer
@@ -300,6 +298,7 @@ var conditionalExpressSession = function (req, res, next) {
       req.path === "/" ||
       req.path === "/favicon.ico" ||
       req.path === "/forgot-password" ||
+      req.path === '/node_modules/jquery/jquery.js' ||
       req.path === "/recover") {
 
     next();
@@ -398,14 +397,8 @@ require('./oauth2/passport');
 var that = this;
 
 app.use(express.favicon(__dirname + '/views/login/assets/favicon.ico'));
-_.each(X.options.datasource.databases, function (orgValue, orgKey, orgList) {
-  "use strict";
-  app.use("/" + orgValue + '/client', express.static('../enyo-client/application', { maxAge: 86400000 }));
-  app.use("/" + orgValue + '/core-extensions', express.static('../enyo-client/extensions', { maxAge: 86400000 }));
-  app.use("/" + orgValue + '/private-extensions', express.static('../../private-extensions', { maxAge: 86400000 }));
-  app.use("/" + orgValue + '/xtuple-extensions', express.static('../../xtuple-extensions', { maxAge: 86400000 }));
-});
 app.use('/assets', express.static('views/login/assets', { maxAge: 86400000 }));
+app.use('/node_modules/jquery', express.static('../node_modules/jquery/dist', { maxAge: 86400000 }));
 
 app.get('/:org/dialog/authorize', oauth2.authorization);
 app.post('/:org/dialog/authorize/decision', oauth2.decision);
@@ -435,16 +428,16 @@ app.get('/:org/logout', routes.logout);
 app.get('/:org/app', routes.app);
 app.get('/:org/debug', routes.debug);
 
-app.get('/:org/analysis', routes.analysis);
 app.all('/:org/credit-card', routes.creditCard);
 app.all('/:org/change-password', routes.changePassword);
 app.all('/:org/client/build/client-code', routes.clientCode);
 app.all('/:org/email', routes.email);
 app.all('/:org/export', routes.exxport);
 app.get('/:org/file', routes.file);
-app.all('/:org/oauth/generate-key', routes.generateOauthKey);
 app.get('/:org/generate-report', routes.generateReport);
+app.all('/:org/install-extension', routes.installExtension);
 app.get('/:org/locale', routes.locale);
+app.all('/:org/oauth/generate-key', routes.generateOauthKey);
 app.get('/:org/reset-password', routes.resetPassword);
 app.post('/:org/oauth/revoke-token', routes.revokeOauthToken);
 app.all('/:org/vcfExport', routes.vcfExport);
@@ -651,10 +644,9 @@ io.of('/clientsock').authorization(function (handshakeData, callback) {
           data: session.passport.user,
           code: 1,
           debugging: X.options.datasource.debugging,
-          biAvailable: _.isObject(X.options.biServer) && !_.isEmpty(X.options.biServer),
           emailAvailable: _.isString(X.options.datasource.smtpHost) && X.options.datasource.smtpHost !== "",
           printAvailable: _.isString(X.options.datasource.printer) && X.options.datasource.printer !== "",
-          version: X.version
+          versions: X.versions
         });
       callback(callbackObj);
     }, data && data.payload);
index 9c5f0ef..d42b742 100644 (file)
@@ -274,8 +274,7 @@ server.exchange(oauth2orize.exchange.refreshToken(function (client, refreshToken
 // signature parts and a done callback. If these values are valid, the
 // application issues an access token on behalf of the user in the JWT `prn`
 // property.
-
-server.exchange('assertion', jwtBearer(function (client, header, claimSet, signature, done) {
+var jwtExchange = function (client, header, claimSet, signature, done) {
   "use strict";
 
   var data = header + "." + claimSet,
@@ -297,10 +296,12 @@ server.exchange('assertion', jwtBearer(function (client, header, claimSet, signa
         expires = new Date(today.getTime() + (60 * 60 * 1000)), // One hour from now.
         token = new SYS.Oauth2token();
 
+
     // Verify JWT was formed correctly.
     if (!decodedHeader || !decodedHeader.alg || !decodedHeader.typ) {
       return done(new Error("Invalid JWT header."));
     }
+
     if (!decodedClaimSet || decodedClaimSet.length < 5 || !decodedClaimSet.iss ||
       !decodedClaimSet.scope || !decodedClaimSet.aud || !decodedClaimSet.exp ||
       !decodedClaimSet.iat) {
@@ -417,16 +418,19 @@ server.exchange('assertion', jwtBearer(function (client, header, claimSet, signa
         token.initialize(null, {isNew: true, database: scopes[0]});
       });
     } else {
-      // No prn, throw error for now.
-      return done(new Error("Invalid JWT. No delegate user."));
-
-      // TODO - Handle public scopes with no delegatedAccess users if we ever need to.
+      // Either there is no prn, OR client.delegatedAccess is not enabled.
+      // TODO: Right now, if you create a service account and uncheck the "delegatedAccess"
+      //   field, then you will see this error. We need to handle public scopes with no
+      //   delegated users here.
+      return done(new Error("Invalid JWT. No delegated user or delegated access is not enabled for this client."));
     }
   } else {
     return done(new Error("Invalid JWT. Signature verification failed"));
   }
-}));
-
+};
+// Support both known grant types.
+server.exchange('assertion', jwtBearer(jwtExchange));
+server.exchange('urn:ietf:params:oauth:grant-type:jwt-bearer', jwtBearer(jwtExchange));
 
 // TODO - We need a token revoke endpoint some day.
 //https://developers.google.com/accounts/docs/OAuth2WebServer#tokenrevoke
diff --git a/node-datasource/routes/analysis.js b/node-datasource/routes/analysis.js
deleted file mode 100644 (file)
index db04345..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
-regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true, _:true, SYS:true */
-
-(function () {
-  "use strict";
-
-  var utils = require('../oauth2/utils');
-
-  /**
-    Generates a JSON Web Token (JWT) to be appended to the
-    BI Server URL so that it may authenticate the current user.
-  */
-  exports.analysis = function (req, res) {
-    var jwt,
-      privKey = "",
-      claimSet = {},
-      header = {},
-      reportUrl = req.query.reportUrl,
-      username = req.session.passport.user.username,
-      biServerHost = X.options.biServer.bihost || "localhost",
-      biServerPortHttps = X.options.biServer.httpsport || "8443",
-      biServerUrl = "https://" + biServerHost + ":" + biServerPortHttps + "/pentaho/",
-      today = new Date(),
-      expires = new Date(today.getTime() + (10 * 60 * 1000)), // 10 minutes from now
-      datasource = "https://" + req.headers.host + "/",
-      database = req.session.passport.user.organization,
-      scope = datasource + database + "/auth/" + database,
-      audience = datasource + database + "/oauth/token",
-      superuser = X.options.databaseServer.user,
-      tenant = X.options.biServer.tenantname || "default",
-      biKeyFile = X.options.biServer.restkeyfile || "";
-
-    // get private key from path in config
-    privKey = X.fs.readFileSync(biKeyFile);
-
-    // create header for JWT
-    header = {
-      "alg": "RS256",
-      "type": "JWT"
-    };
-
-    // create claimSet for JWT
-    claimSet = {
-      "prn": username, // username
-      "scope": scope,
-      "aud": audience,
-      "org": database,
-      "superuser": superuser, // database user
-      "datasource": datasource, // rest api url
-      "exp": Math.round(expires.getTime() / 1000), // expiration date in millis
-      "iat": Math.round(today.getTime() / 1000),  // created date in millis
-      "tenant": tenant || "default" // unique tenant id
-    };
-
-    // encode and sign JWT with private key
-    jwt = encodeJWT(JSON.stringify(header), JSON.stringify(claimSet), privKey);
-    // send newly formed BI url back to the client
-    res.send(biServerUrl + reportUrl + "&assertion=" + jwt.jwt);
-  };
-
-  var encodeJWT = function (header, claimSet, key) {
-    var encodeHeader,
-      encodeClaimSet,
-      signer,
-      signature,
-      data,
-      jwt;
-
-    if (!key) {
-      X.log("No private key");
-    }
-
-    // if there is a problem encoding/signing the JWT, then return invalid
-    try {
-      encodeHeader = utils.base64urlEncode(JSON.stringify(JSON.parse(header)));
-      encodeClaimSet = utils.base64urlEncode(JSON.stringify(JSON.parse(claimSet)));
-      data = encodeHeader + "." + encodeClaimSet;
-
-      signer = X.crypto.createSign("RSA-SHA256");
-      signer.update(data);
-      signature = utils.base64urlEscape(signer.sign(key, "base64"));
-      jwt = {
-        jwt: data + "." + signature
-      };
-
-    } catch (error) {
-      jwt = {
-        jwt: "invalid"
-      };
-      X.log("Invalid JWT");
-    }
-
-    return jwt;
-  };
-
-}());
index bc41f2d..e083ee8 100644 (file)
@@ -40,14 +40,47 @@ var async = require("async"),
     Works with three or four dot-separated numbers.
   */
   var getVersionSize = function (version) {
-    var versionSplit = version.split('.'),
-      versionSize = 1000000 * versionSplit[0] +
-        10000 * versionSplit[1] +
-        100 * versionSplit[2];
+    var versionSplit = version.split('.'),                  // e.g. "4.5.0-beta2".
+      versionSize = 1000000 * versionSplit[0] +             // Get "4" from "4.5.0-beta2".
+        10000 * versionSplit[1] +                           // Get "5" from "4.5.0-beta2".
+        100 * versionSplit[2].match(/^[0-9]+/g, '')[0],     // Get "0" from "0-beta2".
+      prerelease = versionSplit[2].replace(/^[0-9]+/g, ''), // Get "-beta2" from "0-beta2".
+      preRegEx = /([a-zA-Z]+)([0-9]*)/g,                    // Capture pre-release as ["beta2", "beta", "2"].
+      preMatch = preRegEx.exec(prerelease),
+      preVersion,
+      preNum;
 
     if (versionSplit.length > 3) {
       versionSize += versionSplit[3];
     }
+
+    if (preMatch && preMatch.length && preMatch[0] !== '') {
+      if (preMatch[1] !== '') {
+        preVersion = preMatch[1].match(/[a-zA-Z]+/g);       // Get ["beta"] from ["beta2", "beta", "2"].
+
+        // Decrease versionSize for pre-releasees.
+        switch (preVersion[0].toLowerCase()) {
+          case 'alpha':
+            versionSize = versionSize - 50;
+            break;
+          case 'beta':
+            versionSize = versionSize - 40;
+            break;
+          case 'rc':
+            versionSize = versionSize - 20;
+            break;
+          default :
+            X.err("Cannot get pre-release version number.");
+        }
+      }
+
+      // Add pre-release version to versionSize.
+      if (preMatch[2] !== '') {
+        preNum = preMatch[2].match(/[0-9]+/g);              // Get ["2"] from ["beta2", "beta", "2"].
+        versionSize = versionSize + parseInt(preNum);
+      }
+    }
+
     return versionSize;
   };
 
@@ -77,20 +110,30 @@ var async = require("async"),
               return ext1.name > ext2.name ? 1 : -1;
             }
           });
-          var uuids = _.map(extensions, function (ext) {
-            var sortedModels = _.sortBy(ext.codeInfo, function (codeInfo) {
-              return -1 * getVersionSize(codeInfo.version);
+          var getLatestUuid = function (extensions, language) {
+            var uuids = _.map(extensions, function (ext) {
+              var jsModels = _.filter(ext.codeInfo, function (codeInfo) {
+                return codeInfo.language === language;
+              });
+              var sortedModels = _.sortBy(jsModels, function (codeInfo) {
+                return -1 * getVersionSize(codeInfo.version);
+              });
+              if (sortedModels[0]) {
+                return sortedModels[0].uuid;
+              } else {
+                X.log("Could not find js uuid for extension " + ext.description);
+                return null;
+              }
             });
-            if (sortedModels[0]) {
-              return sortedModels[0].uuid;
-            } else {
-              X.log("Could not find uuid for extension " + ext.description);
-              return null;
-            }
-          });
-          uuids = _.compact(uuids); // eliminate any null values
+            return _.compact(uuids); // eliminate any null values
+          };
+          var extJsUuids = getLatestUuid(extensions, "js");
+          var extCssUuids = getLatestUuid(extensions, "css");
           var extensionPaths = _.compact(_.map(extensions, function (ext) {
-            return path.join(ext.location, "source", ext.name);
+            var locationName = ext.location.indexOf("/") === 0 ?
+              path.join(ext.location, "source") :
+              "/" + ext.location;
+            return path.join(locationName, ext.name);
           }));
           getCoreUuid('js', req.session.passport.user.organization, function (err, jsUuid) {
             if (err) {
@@ -106,7 +149,8 @@ var async = require("async"),
                 org: req.session.passport.user.organization,
                 coreJs: jsUuid,
                 coreCss: cssUuid,
-                extensions: uuids,
+                extensionJsArray: extJsUuids,
+                extensionCssArray: extCssUuids,
                 extensionPaths: extensionPaths
               });
             });
index 1f242e8..28e5504 100644 (file)
@@ -19,9 +19,12 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     //passport.authenticate('local', { successReturnToOrRedirect: '/login/scope', failureRedirect: '/', failureFlash: 'Invalid username or password.' }),
     passport.authenticate('local', { failureRedirect: '/?login=fail' }),
     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) {
-        res.redirect("/" + req.session.passport.user.organization + '/app');
+        if (req.body.hash && req.body.hash.charAt(0) === "#") {
+          pathName = pathName + req.body.hash;
+        }
+        res.redirect("/" + req.session.passport.user.organization + pathName);
         //next();
       } else {
         exports.scopeForm(req, res, next);
diff --git a/node-datasource/routes/install_extension.js b/node-datasource/routes/install_extension.js
new file mode 100644 (file)
index 0000000..4f67983
--- /dev/null
@@ -0,0 +1,83 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global X:true, SYS:true, _:true */
+
+(function () {
+  "use strict";
+
+  var async = require("async"),
+    npm = require("npm"),
+    path = require("path"),
+    buildAll = require("../../scripts/lib/build_all");
+
+  exports.installExtension = function (req, res) {
+    var database = req.session.passport.user.organization,
+      extensionName = req.query.extensionName,
+      username = req.session.passport.user.id,
+      user = new SYS.User(),
+      validateInput = function (callback) {
+        if (!extensionName) {
+          callback("Error: empty extension name");
+          return;
+        }
+        callback();
+      },
+      validateUser = function (callback) {
+        user.fetch({
+          id: username,
+          username: X.options.databaseServer.user,
+          database: database,
+          success: function (userModel, results) {
+            userModel.checkPrivilege("InstallExtension", database, callback);
+          },
+          error: function () {
+            callback({message: "_privilegeCheckError"});
+          }
+        });
+      },
+      npmLoad = function (callback) {
+        npm.load(callback);
+      },
+      npmInstall = function (callback) {
+        npm.commands.install([extensionName], callback);
+        npm.on("log", function (message) {
+          // log the progress of the installation
+          console.log(message);
+        });
+      },
+      buildExtension = function (callback) {
+        console.log("extension is", path.join(__dirname, "../../node_modules", extensionName));
+        buildAll.build({
+          database: database,
+          extension: path.join(__dirname, "../../node_modules", extensionName)
+        }, callback);
+      },
+      // make the client-side assets immediately available to the webserver
+      // without the need for a datasource restart
+      useClientDir = function (callback) {
+        X.useClientDir("npm/" + extensionName + "/client",
+          path.join(__dirname, "../../node_modules", extensionName, "client"));
+        callback();
+      };
+
+    async.series([
+      validateInput,
+      validateUser,
+      npmLoad,
+      npmInstall,
+      buildExtension,
+      useClientDir
+    ], function (err, results) {
+      if (err) {
+        err.isError = true;
+        err.errorMessage = err.message;
+        res.send(err);
+        return;
+      }
+      console.log("all done");
+      res.send({data: "_success!"});
+    });
+  };
+}());
+
+
index 4ccea3c..91cee16 100644 (file)
@@ -25,7 +25,6 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     // is a function that returns another function, and express allows routes to
     // be defined in such a way as to chain these types of functions together in an array.
     ensureLogin = require('connect-ensure-login').ensureLoggedIn(logoutPath),
-    analysis = require('./analysis'),
     app = require('./app'),
     auth = require('./auth'),
     authorizeNet = require('./authorize-net'),
@@ -37,6 +36,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     file = require('./file'),
     generateReport = require('./generate_report'),
     generateOauthKey = require('./generate_oauth_key'),
+    installExtension = require('./install_extension'),
     locale = require('./locale'),
     passport = require('passport'),
     redirector = require('./redirector'),
@@ -94,9 +94,9 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
   exports.file = [ensureLogin, file.file];
   exports.generateOauthKey = [ensureLogin, generateOauthKey.generateKey];
   exports.generateReport = [ensureLogin, generateReport.generateReport];
+  exports.installExtension = [ensureLogin, installExtension.installExtension];
   exports.locale = [ensureLogin, locale.locale];
   exports.redirect = redirector.redirect;
-  exports.analysis = [ensureLogin, analysis.analysis];
   exports.resetPassword = [ensureLogin, changePassword.resetPassword];
   exports.revokeOauthToken = [ensureLogin, revokeOauthToken.revokeToken];
   exports.vcfExport = [ensureLogin, vcfExport.vcfExport];
index c1ca279..49fb74e 100644 (file)
     <!-- css -->
     <link href="/<%= org %>/client/lib/enyo-x/lib/nvd3/src/nv.d3.css" rel="stylesheet"/>
     <link href="/<%= org %>/client/build/client-code?uuid=<%= coreCss %>&language=css" rel="stylesheet"/>
+    <% for (var i = 0; i < extensionCssArray.length; i++) { %>
+      <link href="/<%= org %>/client/build/client-code?uuid=<%= extensionCssArray[i] %>&language=css" rel="stylesheet"/>
+    <% } %>
     <!-- js -->
     <script src="/<%= org %>/locale"></script>
     <script src="/socket.io/socket.io.js?1.3.10" type="text/javascript"></script>
+    <script src="/node_modules/jquery/jquery.js"></script>
     <script src="/<%= org %>/client/build/client-code?uuid=<%= coreJs %>&language=js"></script>
-    <% for (var i = 0; i < extensions.length; i++) { %>
-      <script src="/<%= org %>/client/build/client-code?uuid=<%= extensions[i] %>&language=js"></script>
+    <% for (var i = 0; i < extensionJsArray.length; i++) { %>
+      <script src="/<%= org %>/client/build/client-code?uuid=<%= extensionJsArray[i] %>&language=js"></script>
     <% } %>
   </head>
   <body class="enyo-unselectable">
index 41a9971..52e347f 100644 (file)
@@ -18,6 +18,7 @@
     </script>
     <script src="/<%= org %>/client/lib/module/less/dist/less-1.5.0.js"></script>
     <script src="/<%= org %>/client/enyo/enyo.js"></script>
+    <script src="/node_modules/jquery/jquery.js"></script>
     <!-- application (debug) -->
     <link href="/<%= org %>/client/lib/enyo-x/lib/nvd3/src/nv.d3.css" rel="stylesheet"/>
     <script src="/<%= org %>/locale?debug=true"></script>
index bdcd2e3..f5fc09b 100644 (file)
     <section id="main">
       <div style="transform: translateZ(0px); opacity: 1;" id="form-fields">
         <form name="loginForm" action="/login" method="post">
+          <input type="hidden" id="hash" name="hash">
           <div class="login-label" id="form-fields_idLabel">Username</div>
-          <input class="login-input" id="form-fields_id" name="id" placeholder="Username">
+          <input class="login-input" id="form-fields_id" name="id" placeholder="username">
           <div class="login-label" id="form-fields_passwordLabel">Password</div>
-          <input class="login-input" id="form-fields_password" placeholder="Password" name="password" type="password">
+          <input class="login-input" id="form-fields_password" placeholder="password" name="password" type="password" autocapitalize="off" autocorrect="off">
           <div class="login-label" id="form-fields_databaseLabel">Database</div>
           <select class="login-input" id="form-fields_database" name="database">
           <% for(var i = 0; i < databases.length; i++) { %>
     <% } %>
   </section>
 
-  <!-- <div class="footer">
-    <div class="footer-container">
-      <p>
-        Visit the <a href='http://www.xtuple.org/docs/mobile-web-demo-guide'>Mobile Web Demo Guide</a>,
-        or send email to <a href='mailto:demo@xtuple.com'>demo@xtuple.com</a> for help.
-      </p>
-
-      <p>
-        This MOBILE WEB CLIENT provides access the CRM, Project and Sales modules of xTuple.
-        You must use the DESKTOP CLIENT to access the full application, including CRM, Projects, Sales, Purchasing, Inventory, Manufacturing, Scheduling and Accounting modules.
-      </p>
-
-      <p>
-        Download the xTuple Desktop client here: <a href=''>Windows</a>,
-        <a href=''>Mac</a>, <a href=''>Linux</a>
-      </p>
-
-      <p>v1.4.5</p>
-    </div>
-  </div> -->
-
   <script>
     document.loginForm.id.focus();
+    document.loginForm.hash.value = window.location.hash;
   </script>
   </body>
 </html>
index cd42baa..0435977 100644 (file)
@@ -183,7 +183,6 @@ label.login-message-box.error {
   display: block;
   width: 97%;
   margin: 0;
-  text-transform: lowercase;
   outline: none;
   color: #666666;
   font-smoothing: antialiased;
index f00146a..6e28736 100644 (file)
@@ -113,9 +113,5 @@ XT = { };
     // give any running process the opportunity to save state
     // or log as gracefully as possible
     process.once('exit', _.bind(X.cleanup, X));
-
-    _.forEach(["SIGINT", "SIGHUP", "SIGQUIT", "SIGKILL", "SIGSEGV", "SIGILL"], function (sig) {
-      process.once(sig, _.bind(sighandler, X, sig));
-    });
   });
 }());
index 40bfd2c..8feddec 100644 (file)
@@ -1,10 +1,11 @@
 {
   "name": "xtuple",
-  "version": "4.4.1",
+  "version": "4.7.0-beta",
   "dependencies": {
     "async": {
       "version": "0.2.10",
-      "from": "async@0.2.x"
+      "from": "async@0.2.x",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
     },
     "backbone": {
       "version": "0.9.10",
     },
     "backbone-relational": {
       "version": "0.8.0",
-      "from": "backbone-relational@0.8.0",
-      "resolved": "https://registry.npmjs.org/backbone-relational/-/backbone-relational-0.8.0.tgz"
+      "from": "backbone-relational@0.8.0"
     },
     "bcrypt": {
       "version": "0.7.8",
       "from": "bcrypt@0.7.x",
-      "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-0.7.8.tgz",
       "dependencies": {
         "bindings": {
           "version": "1.0.0",
-          "from": "bindings@1.0.0",
-          "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.0.0.tgz"
+          "from": "bindings@1.0.0"
         }
       }
     },
+    "chai": {
+      "version": "1.5.0",
+      "from": "chai@1.5.x",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-1.5.0.tgz"
+    },
     "colors": {
       "version": "0.6.2",
       "from": "colors@0.6.x"
@@ -35,6 +38,7 @@
     "commander": {
       "version": "1.2.0",
       "from": "commander@1.2.x",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-1.2.0.tgz",
       "dependencies": {
         "keypress": {
           "version": "0.1.0",
       "version": "0.1.1",
       "from": "connect-ensure-login@0.1.x"
     },
+    "csslint": {
+      "version": "0.10.0",
+      "from": "csslint@~0.10.0",
+      "resolved": "https://registry.npmjs.org/csslint/-/csslint-0.10.0.tgz",
+      "dependencies": {
+        "parserlib": {
+          "version": "0.2.5",
+          "from": "parserlib@~0.2.2"
+        }
+      }
+    },
     "ejs": {
       "version": "0.8.8",
       "from": "ejs@0.8.x"
     "express": {
       "version": "3.1.2",
       "from": "express@3.1.x",
+      "resolved": "https://registry.npmjs.org/express/-/express-3.1.2.tgz",
       "dependencies": {
         "connect": {
           "version": "2.7.5",
           "from": "connect@2.7.5",
+          "resolved": "https://registry.npmjs.org/connect/-/connect-2.7.5.tgz",
           "dependencies": {
             "qs": {
               "version": "0.5.1",
-              "from": "qs@0.5.1"
+              "from": "qs@0.5.1",
+              "resolved": "https://registry.npmjs.org/qs/-/qs-0.5.1.tgz"
             },
             "formidable": {
               "version": "1.0.11",
         },
         "cookie": {
           "version": "0.0.5",
-          "from": "cookie@0.0.5"
+          "from": "cookie@0.0.5",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.0.5.tgz"
         },
         "buffer-crc32": {
-          "version": "0.2.1",
-          "from": "buffer-crc32@~0.2.1"
+          "version": "0.2.3",
+          "from": "buffer-crc32@~0.2.1",
+          "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.3.tgz"
         },
         "fresh": {
           "version": "0.1.0",
         },
         "methods": {
           "version": "0.0.1",
-          "from": "methods@0.0.1"
+          "from": "methods@0.0.1",
+          "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz"
         },
         "send": {
           "version": "0.1.0",
           "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.0.tgz"
         },
         "debug": {
-          "version": "0.8.1",
+          "version": "1.0.4",
           "from": "debug@*",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz"
+          "dependencies": {
+            "ms": {
+              "version": "0.6.2",
+              "from": "ms@0.6.2"
+            }
+          }
         }
       }
     },
         }
       }
     },
-    "ipp": {
-      "version": "0.0.5",
-      "from": "ipp@0.0.5",
-      "resolved": "https://registry.npmjs.org/ipp/-/ipp-0.0.5.tgz"
-    },
-    "json-patch": {
-      "version": "0.0.1",
-      "from": "json-patch@git://github.com/xtuple/JSON-Patch.git",
-      "resolved": "git://github.com/xtuple/JSON-Patch.git#eb69a78f6d041b2f630a9747a5b227c42c8df077"
-    },
-    "less": {
-      "version": "1.5.0",
-      "from": "less@1.5.0",
-      "resolved": "https://registry.npmjs.org/less/-/less-1.5.0.tgz",
+    "googleapis": {
+      "version": "0.4.7",
+      "from": "googleapis@~0.4.6",
+      "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-0.4.7.tgz",
       "dependencies": {
-        "mime": {
-          "version": "1.2.11",
-          "from": "mime@1.2.x",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
-        },
-        "mkdirp": {
-          "version": "0.3.5",
-          "from": "mkdirp@~0.3.4"
-        },
-        "clean-css": {
-          "version": "1.0.12",
-          "from": "clean-css@1.0.x",
+        "request": {
+          "version": "2.25.0",
+          "from": "request@~2.25.0",
           "dependencies": {
-            "commander": {
-              "version": "1.3.2",
-              "from": "commander@1.3.x",
+            "qs": {
+              "version": "0.6.6",
+              "from": "qs@~0.6.0"
+            },
+            "json-stringify-safe": {
+              "version": "5.0.0",
+              "from": "json-stringify-safe@~5.0.0"
+            },
+            "forever-agent": {
+              "version": "0.5.2",
+              "from": "forever-agent@~0.5.0"
+            },
+            "tunnel-agent": {
+              "version": "0.3.0",
+              "from": "tunnel-agent@~0.3.0"
+            },
+            "http-signature": {
+              "version": "0.10.0",
+              "from": "http-signature@~0.10.0",
               "dependencies": {
-                "keypress": {
-                  "version": "0.1.0",
-                  "from": "keypress@0.1.x"
+                "assert-plus": {
+                  "version": "0.1.2",
+                  "from": "assert-plus@0.1.2",
+                  "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz"
+                },
+                "asn1": {
+                  "version": "0.1.11",
+                  "from": "asn1@0.1.11",
+                  "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+                },
+                "ctype": {
+                  "version": "0.5.2",
+                  "from": "ctype@0.5.2"
                 }
               }
-            }
-          }
-        },
-        "source-map": {
-          "version": "0.1.33",
-          "from": "source-map@0.1.x",
-          "dependencies": {
-            "amdefine": {
-              "version": "0.1.0",
-              "from": "amdefine@>=0.0.4"
-            }
-          }
-        }
-      }
-    },
-    "moment": {
-      "version": "2.4.0",
-      "from": "moment@2.4.x"
-    },
-    "nodemailer": {
-      "version": "0.3.44",
-      "from": "nodemailer@0.3.x",
-      "dependencies": {
-        "mailcomposer": {
-          "version": "0.2.9",
-          "from": "mailcomposer@>= 0.1.29",
-          "dependencies": {
-            "mimelib": {
-              "version": "0.2.14",
-              "from": "mimelib@~0.2.14",
+            },
+            "hawk": {
+              "version": "1.0.0",
+              "from": "hawk@~1.0.0",
               "dependencies": {
-                "encoding": {
-                  "version": "0.1.7",
-                  "from": "encoding@~0.1",
-                  "dependencies": {
-                    "iconv-lite": {
-                      "version": "0.2.11",
-                      "from": "iconv-lite@~0.2.11"
-                    }
-                  }
+                "hoek": {
+                  "version": "0.9.1",
+                  "from": "hoek@0.9.x"
                 },
-                "addressparser": {
-                  "version": "0.2.1",
-                  "from": "addressparser@~0.2.0"
+                "boom": {
+                  "version": "0.4.2",
+                  "from": "boom@0.4.x"
+                },
+                "cryptiles": {
+                  "version": "0.2.2",
+                  "from": "cryptiles@0.2.x"
+                },
+                "sntp": {
+                  "version": "0.2.4",
+                  "from": "sntp@0.2.x"
                 }
               }
             },
-            "mime": {
-              "version": "1.2.11",
-              "from": "mime@~1.2.9",
-              "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
+            "aws-sign": {
+              "version": "0.3.0",
+              "from": "aws-sign@~0.3.0"
             },
-            "he": {
-              "version": "0.3.6",
-              "from": "he@~0.3.6"
+            "oauth-sign": {
+              "version": "0.3.0",
+              "from": "oauth-sign@~0.3.0"
             },
-            "punycode": {
-              "version": "1.2.4",
-              "from": "punycode@~1.2.3"
+            "cookie-jar": {
+              "version": "0.3.0",
+              "from": "cookie-jar@~0.3.0"
             },
-            "follow-redirects": {
-              "version": "0.0.3",
-              "from": "follow-redirects@0.0.3",
-              "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.3.tgz"
+            "node-uuid": {
+              "version": "1.4.1",
+              "from": "node-uuid@~1.4.0"
             },
-            "dkim-signer": {
-              "version": "0.1.0",
-              "from": "dkim-signer@~0.1.0"
-            }
-          }
-        },
-        "simplesmtp": {
-          "version": "0.3.29",
-          "from": "simplesmtp@>= 0.1.28",
-          "resolved": "https://registry.npmjs.org/simplesmtp/-/simplesmtp-0.3.29.tgz",
-          "dependencies": {
-            "rai": {
-              "version": "0.1.10",
-              "from": "rai@~0.1.10",
-              "resolved": "https://registry.npmjs.org/rai/-/rai-0.1.10.tgz"
+            "mime": {
+              "version": "1.2.11",
+              "from": "mime@~1.2.9"
             },
-            "xoauth2": {
-              "version": "0.1.8",
-              "from": "xoauth2@~0.1"
+            "form-data": {
+              "version": "0.1.4",
+              "from": "form-data@~0.1.0",
+              "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
+              "dependencies": {
+                "combined-stream": {
+                  "version": "0.0.5",
+                  "from": "combined-stream@~0.0.4",
+                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.5.tgz",
+                  "dependencies": {
+                    "delayed-stream": {
+                      "version": "0.0.5",
+                      "from": "delayed-stream@0.0.5",
+                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
+                    }
+                  }
+                },
+                "async": {
+                  "version": "0.9.0",
+                  "from": "async@~0.9.0"
+                }
+              }
             }
           }
         },
-        "optimist": {
-          "version": "0.6.1",
-          "from": "optimist@*",
+        "async": {
+          "version": "0.2.6",
+          "from": "async@0.2.6",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz"
+        },
+        "gapitoken": {
+          "version": "0.1.0",
+          "from": "gapitoken@0.1.0",
+          "resolved": "https://registry.npmjs.org/gapitoken/-/gapitoken-0.1.0.tgz",
           "dependencies": {
-            "wordwrap": {
+            "jws": {
               "version": "0.0.2",
-              "from": "wordwrap@~0.0.2"
-            },
-            "minimist": {
-              "version": "0.0.9",
-              "from": "minimist@~0.0.1",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.9.tgz"
-            }
-          }
-        }
-      }
-    },
-    "node-forge": {
-      "version": "0.6.2",
-      "from": "node-forge@0.6.x"
-    },
-    "oauth2orize": {
-      "version": "0.1.0",
-      "from": "oauth2orize@0.1.x",
-      "dependencies": {
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@0.7.x"
-        }
-      }
-    },
-    "oauth2orize-jwt-bearer": {
-      "version": "0.1.0",
-      "from": "oauth2orize-jwt-bearer@0.1.x",
-      "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
-        }
-      }
-    },
-    "passport": {
-      "version": "0.1.18",
-      "from": "passport@0.1.x",
-      "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
-        },
-        "pause": {
-          "version": "0.0.1",
-          "from": "pause@0.0.1"
-        }
-      }
-    },
-    "passport-http": {
-      "version": "0.2.2",
-      "from": "passport-http@0.2.x",
-      "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
-        }
-      }
-    },
-    "passport-http-bearer": {
-      "version": "0.2.1",
-      "from": "passport-http-bearer@0.2.x",
-      "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
-        }
+              "from": "jws@0.0.2",
+              "resolved": "https://registry.npmjs.org/jws/-/jws-0.0.2.tgz",
+              "dependencies": {
+                "tap": {
+                  "version": "0.3.3",
+                  "from": "tap@~0.3.3",
+                  "dependencies": {
+                    "inherits": {
+                      "version": "1.0.0"
+                    },
+                    "yamlish": {
+                      "version": "0.0.5"
+                    },
+                    "slide": {
+                      "version": "1.1.5",
+                      "from": "slide@*"
+                    },
+                    "runforcover": {
+                      "version": "0.0.2",
+                      "from": "runforcover@~0.0.2",
+                      "dependencies": {
+                        "bunker": {
+                          "version": "0.1.2",
+                          "from": "bunker@0.1.X",
+                          "dependencies": {
+                            "burrito": {
+                              "version": "0.2.12",
+                              "from": "burrito@>=0.2.5 <0.3",
+                              "dependencies": {
+                                "traverse": {
+                                  "version": "0.5.2",
+                                  "from": "traverse@~0.5.1"
+                                },
+                                "uglify-js": {
+                                  "version": "1.1.1",
+                                  "from": "uglify-js@~1.1.1",
+                                  "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.1.1.tgz"
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "nopt": {
+                      "version": "2.2.1",
+                      "from": "nopt@~2",
+                      "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz",
+                      "dependencies": {
+                        "abbrev": {
+                          "version": "1.0.5",
+                          "from": "abbrev@1",
+                          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
+                        }
+                      }
+                    },
+                    "mkdirp": {
+                      "version": "0.3.5",
+                      "from": "mkdirp@~0.3"
+                    },
+                    "difflet": {
+                      "version": "0.2.6",
+                      "from": "difflet@~0.2.0",
+                      "dependencies": {
+                        "traverse": {
+                          "version": "0.6.6",
+                          "from": "traverse@0.6.x"
+                        },
+                        "charm": {
+                          "version": "0.1.2",
+                          "from": "charm@0.1.x"
+                        },
+                        "deep-is": {
+                          "version": "0.1.3",
+                          "from": "deep-is@0.1.x",
+                          "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
+                        }
+                      }
+                    },
+                    "deep-equal": {
+                      "version": "0.0.0",
+                      "from": "deep-equal@~0.0.0"
+                    },
+                    "buffer-equal": {
+                      "version": "0.0.1",
+                      "from": "buffer-equal@~0.0.0"
+                    }
+                  }
+                },
+                "base64url": {
+                  "version": "0.0.3",
+                  "from": "base64url@0.0.3",
+                  "resolved": "https://registry.npmjs.org/base64url/-/base64url-0.0.3.tgz"
+                }
+              }
+            }
+          }
+        }
       }
     },
-    "passport-local": {
-      "version": "0.1.6",
-      "from": "passport-local@0.1.x",
+    "html5": {
+      "version": "0.3.13",
+      "from": "html5@0.3.13",
+      "resolved": "https://registry.npmjs.org/html5/-/html5-0.3.13.tgz",
       "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
+        "jsdom": {
+          "version": "1.0.0-pre.3",
+          "from": "jsdom@>= 0.6.0",
+          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-1.0.0-pre.3.tgz",
+          "dependencies": {
+            "htmlparser2": {
+              "version": "3.7.3",
+              "from": "htmlparser2@>= 3.1.5 <4",
+              "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.7.3.tgz",
+              "dependencies": {
+                "domhandler": {
+                  "version": "2.2.0",
+                  "from": "domhandler@2.2"
+                },
+                "domutils": {
+                  "version": "1.5.0",
+                  "from": "domutils@1.5"
+                },
+                "domelementtype": {
+                  "version": "1.1.1",
+                  "from": "domelementtype@1"
+                },
+                "readable-stream": {
+                  "version": "1.1.13",
+                  "from": "readable-stream@1.1",
+                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+                  "dependencies": {
+                    "core-util-is": {
+                      "version": "1.0.1",
+                      "from": "core-util-is@~1.0.0"
+                    },
+                    "isarray": {
+                      "version": "0.0.1",
+                      "from": "isarray@0.0.1"
+                    },
+                    "string_decoder": {
+                      "version": "0.10.31",
+                      "from": "string_decoder@~0.10.x",
+                      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "from": "inherits@~2.0.1"
+                    }
+                  }
+                },
+                "entities": {
+                  "version": "1.0.0",
+                  "from": "entities@1.0"
+                }
+              }
+            },
+            "parse5": {
+              "version": "1.0.1",
+              "from": "parse5@~1.0.1",
+              "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.0.1.tgz"
+            },
+            "nwmatcher": {
+              "version": "1.3.3",
+              "from": "nwmatcher@~1.3.2"
+            },
+            "xmlhttprequest": {
+              "version": "1.6.0",
+              "from": "xmlhttprequest@>=1.5.0"
+            },
+            "cssom": {
+              "version": "0.3.0",
+              "from": "cssom@~0.3.0"
+            },
+            "cssstyle": {
+              "version": "0.2.14",
+              "from": "cssstyle@~0.2.9"
+            },
+            "contextify": {
+              "version": "0.1.8",
+              "from": "contextify@~0.1.5",
+              "dependencies": {
+                "bindings": {
+                  "version": "1.2.1",
+                  "from": "bindings@*",
+                  "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
+                },
+                "nan": {
+                  "version": "1.0.0",
+                  "from": "nan@~1.0.0"
+                }
+              }
+            }
+          }
+        },
+        "opts": {
+          "version": "1.2.2",
+          "from": "opts@~1.2.1"
+        },
+        "html5-entities": {
+          "version": "0.5.1",
+          "from": "html5-entities@~0.5.0",
+          "resolved": "https://registry.npmjs.org/html5-entities/-/html5-entities-0.5.1.tgz"
+        }
+      }
+    },
+    "ipp": {
+      "version": "0.0.5",
+      "from": "ipp@0.0.5"
+    },
+    "jquery": {
+      "version": "2.1.1",
+      "from": "jquery@~2.1.1",
+      "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.1.1.tgz"
+    },
+    "jshint": {
+      "version": "2.4.4",
+      "from": "jshint@2.4.x",
+      "dependencies": {
+        "shelljs": {
+          "version": "0.1.4",
+          "from": "shelljs@0.1.x"
+        },
+        "cli": {
+          "version": "0.4.5",
+          "from": "cli@0.4.x",
+          "dependencies": {
+            "glob": {
+              "version": "4.0.5",
+              "from": "glob@>= 3.1.4",
+              "resolved": "https://registry.npmjs.org/glob/-/glob-4.0.5.tgz",
+              "dependencies": {
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@2"
+                },
+                "minimatch": {
+                  "version": "1.0.0",
+                  "from": "minimatch@^1.0.0",
+                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "2.5.0",
+                      "from": "lru-cache@2"
+                    },
+                    "sigmund": {
+                      "version": "1.0.0",
+                      "from": "sigmund@~1.0.0"
+                    }
+                  }
+                },
+                "once": {
+                  "version": "1.3.0",
+                  "from": "once@^1.3.0",
+                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.0.tgz"
+                },
+                "graceful-fs": {
+                  "version": "3.0.2",
+                  "from": "graceful-fs@^3.0.2",
+                  "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.2.tgz"
+                }
+              }
+            }
+          }
+        },
+        "minimatch": {
+          "version": "0.4.0",
+          "from": "minimatch@0.x.x",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.4.0.tgz",
+          "dependencies": {
+            "lru-cache": {
+              "version": "2.5.0",
+              "from": "lru-cache@2"
+            },
+            "sigmund": {
+              "version": "1.0.0",
+              "from": "sigmund@~1.0.0"
+            }
+          }
+        },
+        "htmlparser2": {
+          "version": "3.3.0",
+          "from": "htmlparser2@3.3.x",
+          "dependencies": {
+            "domhandler": {
+              "version": "2.1.0",
+              "from": "domhandler@2.1"
+            },
+            "domutils": {
+              "version": "1.1.6",
+              "from": "domutils@1.1"
+            },
+            "domelementtype": {
+              "version": "1.1.1",
+              "from": "domelementtype@1"
+            },
+            "readable-stream": {
+              "version": "1.0.31",
+              "from": "readable-stream@1.0",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz",
+              "dependencies": {
+                "core-util-is": {
+                  "version": "1.0.1",
+                  "from": "core-util-is@~1.0.0"
+                },
+                "isarray": {
+                  "version": "0.0.1",
+                  "from": "isarray@0.0.1"
+                },
+                "string_decoder": {
+                  "version": "0.10.31",
+                  "from": "string_decoder@~0.10.x",
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@~2.0.1"
+                }
+              }
+            }
+          }
+        },
+        "console-browserify": {
+          "version": "0.1.6",
+          "from": "console-browserify@0.1.x"
+        },
+        "exit": {
+          "version": "0.1.2",
+          "from": "exit@0.1.x"
+        }
+      }
+    },
+    "json-patch": {
+      "version": "0.0.1",
+      "from": "json-patch@git://github.com/xtuple/JSON-Patch.git",
+      "resolved": "git://github.com/xtuple/JSON-Patch.git#eb69a78f6d041b2f630a9747a5b227c42c8df077"
+    },
+    "less": {
+      "version": "1.5.0",
+      "from": "less@1.5.0",
+      "resolved": "https://registry.npmjs.org/less/-/less-1.5.0.tgz",
+      "dependencies": {
+        "mime": {
+          "version": "1.2.11",
+          "from": "mime@~1.2.7"
+        },
+        "mkdirp": {
+          "version": "0.3.5",
+          "from": "mkdirp@~0.3.4"
+        },
+        "clean-css": {
+          "version": "1.0.12",
+          "from": "clean-css@1.0.x",
+          "dependencies": {
+            "commander": {
+              "version": "1.3.2",
+              "from": "commander@1.3.x",
+              "dependencies": {
+                "keypress": {
+                  "version": "0.1.0",
+                  "from": "keypress@0.1.x"
+                }
+              }
+            }
+          }
+        },
+        "source-map": {
+          "version": "0.1.38",
+          "from": "source-map@0.1.x",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.38.tgz",
+          "dependencies": {
+            "amdefine": {
+              "version": "0.1.0",
+              "from": "amdefine@>=0.0.4"
+            }
+          }
+        }
+      }
+    },
+    "mocha": {
+      "version": "1.9.0",
+      "from": "mocha@1.9.x",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.9.0.tgz",
+      "dependencies": {
+        "commander": {
+          "version": "0.6.1",
+          "from": "commander@0.6.1"
+        },
+        "growl": {
+          "version": "1.7.0",
+          "from": "growl@1.7.x"
+        },
+        "jade": {
+          "version": "0.26.3",
+          "from": "jade@0.26.3",
+          "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz",
+          "dependencies": {
+            "mkdirp": {
+              "version": "0.3.0",
+              "from": "mkdirp@0.3.0"
+            }
+          }
+        },
+        "diff": {
+          "version": "1.0.2",
+          "from": "diff@1.0.2"
+        },
+        "debug": {
+          "version": "1.0.4",
+          "from": "debug@*",
+          "dependencies": {
+            "ms": {
+              "version": "0.6.2",
+              "from": "ms@0.6.2"
+            }
+          }
+        },
+        "mkdirp": {
+          "version": "0.3.3",
+          "from": "mkdirp@0.3.3"
+        },
+        "ms": {
+          "version": "0.3.0",
+          "from": "ms@0.3.0"
         }
       }
     },
-    "passport-oauth2-client-password": {
-      "version": "0.1.1",
-      "from": "passport-oauth2-client-password@0.1.x",
-      "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
-        }
-      }
+    "moment": {
+      "version": "2.4.0",
+      "from": "moment@2.4.x",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.4.0.tgz"
     },
-    "passport-oauth2-jwt-bearer": {
-      "version": "0.1.1",
-      "from": "passport-oauth2-jwt-bearer@0.1.x",
+    "node-forge": {
+      "version": "0.6.12",
+      "from": "node-forge@0.6.x",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.12.tgz"
+    },
+    "nodemailer": {
+      "version": "0.3.44",
+      "from": "nodemailer@0.3.x",
+      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-0.3.44.tgz",
       "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
+        "mailcomposer": {
+          "version": "0.2.12",
+          "from": "mailcomposer@>= 0.1.29",
+          "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-0.2.12.tgz",
+          "dependencies": {
+            "mimelib": {
+              "version": "0.2.17",
+              "from": "mimelib@~0.2.15",
+              "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.17.tgz",
+              "dependencies": {
+                "encoding": {
+                  "version": "0.1.8",
+                  "from": "encoding@~0.1.7",
+                  "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.8.tgz",
+                  "dependencies": {
+                    "iconv-lite": {
+                      "version": "0.4.4",
+                      "from": "iconv-lite@~0.4.3",
+                      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.4.tgz"
+                    }
+                  }
+                },
+                "addressparser": {
+                  "version": "0.2.1",
+                  "from": "addressparser@~0.2.1"
+                }
+              }
+            },
+            "mime": {
+              "version": "1.2.11",
+              "from": "mime@1.2.x"
+            },
+            "he": {
+              "version": "0.3.6",
+              "from": "he@~0.3.6"
+            },
+            "follow-redirects": {
+              "version": "0.0.3",
+              "from": "follow-redirects@0.0.3",
+              "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.3.tgz"
+            },
+            "dkim-signer": {
+              "version": "0.1.2",
+              "from": "dkim-signer@~0.1.1",
+              "dependencies": {
+                "punycode": {
+                  "version": "1.2.4",
+                  "from": "punycode@~1.2.4"
+                }
+              }
+            }
+          }
+        },
+        "simplesmtp": {
+          "version": "0.3.32",
+          "from": "simplesmtp@>= 0.1.28",
+          "dependencies": {
+            "rai": {
+              "version": "0.1.11",
+              "from": "rai@~0.1.11"
+            },
+            "xoauth2": {
+              "version": "0.1.8",
+              "from": "xoauth2@~0.1.8"
+            }
+          }
+        },
+        "optimist": {
+          "version": "0.6.1",
+          "from": "optimist@*",
+          "dependencies": {
+            "wordwrap": {
+              "version": "0.0.2",
+              "from": "wordwrap@~0.0.2"
+            },
+            "minimist": {
+              "version": "0.0.10",
+              "from": "minimist@~0.0.1"
+            }
+          }
         }
       }
     },
-    "paynode": {
-      "version": "0.3.6",
-      "from": "paynode@0.3.6",
-      "resolved": "https://registry.npmjs.org/paynode/-/paynode-0.3.6.tgz",
+    "nodemon": {
+      "version": "1.0.20",
+      "from": "nodemon@~1.0.15",
       "dependencies": {
-        "braintree": {
-          "version": "1.14.0",
-          "from": "braintree@*",
+        "update-notifier": {
+          "version": "0.1.10",
+          "from": "update-notifier@~0.1.8",
           "dependencies": {
-            "dateformat": {
-              "version": "1.0.1-1.2.3",
-              "from": "dateformat@=1.0.1-1.2.3",
-              "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.1-1.2.3.tgz"
-            },
-            "semver": {
-              "version": "2.2.1",
-              "from": "semver@=2.2.1",
-              "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz"
-            },
-            "readable-stream": {
-              "version": "1.1.10",
-              "from": "readable-stream@=1.1.10",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.10.tgz",
+            "chalk": {
+              "version": "0.4.0",
+              "from": "chalk@^0.4.0",
               "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@~1.0.0"
+                "has-color": {
+                  "version": "0.1.7",
+                  "from": "has-color@~0.1.0"
                 },
-                "string_decoder": {
-                  "version": "0.10.25-1",
-                  "from": "string_decoder@~0.10.x"
+                "ansi-styles": {
+                  "version": "1.0.0",
+                  "from": "ansi-styles@~1.0.0"
                 },
-                "debuglog": {
-                  "version": "0.0.2",
-                  "from": "debuglog@0.0.2",
-                  "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-0.0.2.tgz"
+                "strip-ansi": {
+                  "version": "0.1.1",
+                  "from": "strip-ansi@~0.1.0"
                 }
               }
             },
-            "underscore": {
-              "version": "1.3.1",
-              "from": "underscore@=1.3.1",
-              "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.3.1.tgz"
-            },
-            "xml2js": {
-              "version": "0.1.13",
-              "from": "xml2js@=0.1.13",
+            "configstore": {
+              "version": "0.3.1",
+              "from": "configstore@^0.3.0",
+              "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.3.1.tgz",
               "dependencies": {
-                "sax": {
-                  "version": "0.6.0",
-                  "from": "sax@>=0.1.1"
+                "graceful-fs": {
+                  "version": "3.0.2",
+                  "from": "graceful-fs@^3.0.2",
+                  "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.2.tgz"
+                },
+                "js-yaml": {
+                  "version": "3.0.2",
+                  "from": "js-yaml@~3.0.1",
+                  "dependencies": {
+                    "argparse": {
+                      "version": "0.1.15",
+                      "from": "argparse@~ 0.1.11"
+                    },
+                    "esprima": {
+                      "version": "1.0.4",
+                      "from": "esprima@~ 1.0.2"
+                    }
+                  }
+                },
+                "mkdirp": {
+                  "version": "0.5.0",
+                  "from": "mkdirp@~0.5.0",
+                  "dependencies": {
+                    "minimist": {
+                      "version": "0.0.8",
+                      "from": "minimist@0.0.8",
+                      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+                    }
+                  }
+                },
+                "object-assign": {
+                  "version": "0.3.1",
+                  "from": "object-assign@~0.3.1",
+                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-0.3.1.tgz"
+                },
+                "osenv": {
+                  "version": "0.1.0",
+                  "from": "osenv@~0.1.0",
+                  "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.0.tgz"
+                },
+                "uuid": {
+                  "version": "1.4.1",
+                  "from": "uuid@~1.4.1"
                 }
               }
             },
-            "source-map-support": {
-              "version": "0.1.2",
-              "from": "source-map-support@=0.1.2",
-              "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.1.2.tgz",
+            "request": {
+              "version": "2.40.0",
+              "from": "request@^2.36.0",
+              "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz",
               "dependencies": {
-                "source-map": {
-                  "version": "0.1.8",
-                  "from": "source-map@0.1.8",
-                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.8.tgz",
+                "qs": {
+                  "version": "1.0.2",
+                  "from": "qs@~1.0.0",
+                  "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz"
+                },
+                "json-stringify-safe": {
+                  "version": "5.0.0",
+                  "from": "json-stringify-safe@~5.0.0"
+                },
+                "mime-types": {
+                  "version": "1.0.2",
+                  "from": "mime-types@~1.0.1",
+                  "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz"
+                },
+                "forever-agent": {
+                  "version": "0.5.2",
+                  "from": "forever-agent@~0.5.0"
+                },
+                "node-uuid": {
+                  "version": "1.4.1",
+                  "from": "node-uuid@~1.4.0"
+                },
+                "tough-cookie": {
+                  "version": "0.12.1",
+                  "from": "tough-cookie@>=0.12.0",
                   "dependencies": {
-                    "amdefine": {
-                      "version": "0.1.0",
-                      "from": "amdefine@>=0.0.4"
+                    "punycode": {
+                      "version": "1.3.1",
+                      "from": "punycode@>=0.2.0",
+                      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.1.tgz"
+                    }
+                  }
+                },
+                "form-data": {
+                  "version": "0.1.4",
+                  "from": "form-data@~0.1.0",
+                  "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
+                  "dependencies": {
+                    "combined-stream": {
+                      "version": "0.0.5",
+                      "from": "combined-stream@~0.0.4",
+                      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.5.tgz",
+                      "dependencies": {
+                        "delayed-stream": {
+                          "version": "0.0.5",
+                          "from": "delayed-stream@0.0.5",
+                          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
+                        }
+                      }
+                    },
+                    "mime": {
+                      "version": "1.2.11",
+                      "from": "mime@~1.2.11"
+                    },
+                    "async": {
+                      "version": "0.9.0",
+                      "from": "async@~0.9.0"
+                    }
+                  }
+                },
+                "tunnel-agent": {
+                  "version": "0.4.0",
+                  "from": "tunnel-agent@~0.4.0",
+                  "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.0.tgz"
+                },
+                "http-signature": {
+                  "version": "0.10.0",
+                  "from": "http-signature@~0.10.0",
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "0.1.2",
+                      "from": "assert-plus@0.1.2",
+                      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz"
+                    },
+                    "asn1": {
+                      "version": "0.1.11",
+                      "from": "asn1@0.1.11",
+                      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+                    },
+                    "ctype": {
+                      "version": "0.5.2",
+                      "from": "ctype@0.5.2"
+                    }
+                  }
+                },
+                "oauth-sign": {
+                  "version": "0.3.0",
+                  "from": "oauth-sign@~0.3.0"
+                },
+                "hawk": {
+                  "version": "1.1.1",
+                  "from": "hawk@1.1.1",
+                  "dependencies": {
+                    "hoek": {
+                      "version": "0.9.1",
+                      "from": "hoek@0.9.x"
+                    },
+                    "boom": {
+                      "version": "0.4.2",
+                      "from": "boom@0.4.x"
+                    },
+                    "cryptiles": {
+                      "version": "0.2.2",
+                      "from": "cryptiles@0.2.x"
+                    },
+                    "sntp": {
+                      "version": "0.2.4",
+                      "from": "sntp@0.2.x"
                     }
                   }
+                },
+                "aws-sign2": {
+                  "version": "0.5.0",
+                  "from": "aws-sign2@~0.5.0"
+                },
+                "stringstream": {
+                  "version": "0.0.4",
+                  "from": "stringstream@~0.0.4",
+                  "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz"
                 }
               }
+            },
+            "semver": {
+              "version": "2.3.2",
+              "from": "semver@^2.3.0",
+              "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz"
             }
           }
-        }
-      }
-    },
-    "pg": {
-      "version": "0.14.1",
-      "from": "pg@0.14.x",
-      "dependencies": {
-        "generic-pool": {
-          "version": "2.0.4",
-          "from": "generic-pool@~2.0.2"
         },
-        "deprecate": {
-          "version": "0.1.0",
-          "from": "deprecate@~0.1.0"
-        }
-      }
-    },
-    "request": {
-      "version": "2.14.0",
-      "from": "request@2.14.x",
-      "dependencies": {
-        "form-data": {
-          "version": "0.0.7",
-          "from": "form-data@~0.0.3",
+        "minimatch": {
+          "version": "0.2.14",
+          "from": "minimatch@~0.2.14",
           "dependencies": {
-            "combined-stream": {
-              "version": "0.0.4",
-              "from": "combined-stream@~0.0.4",
-              "dependencies": {
-                "delayed-stream": {
-                  "version": "0.0.5",
-                  "from": "delayed-stream@0.0.5"
-                }
-              }
+            "lru-cache": {
+              "version": "2.5.0",
+              "from": "lru-cache@2"
             },
-            "async": {
-              "version": "0.1.22",
-              "from": "async@~0.1.9"
+            "sigmund": {
+              "version": "1.0.0",
+              "from": "sigmund@~1.0.0"
             }
           }
         },
-        "mime": {
-          "version": "1.2.9",
-          "from": "mime@~1.2.7"
-        }
-      }
-    },
-    "rimraf": {
-      "version": "2.2.8",
-      "from": "rimraf@2.2.x",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
-    },
-    "rjson": {
-      "version": "0.2.4",
-      "from": "rjson@~0.2.4",
-      "dependencies": {
-        "commander": {
-          "version": "1.1.1",
-          "from": "commander@~1.1.1",
+        "ps-tree": {
+          "version": "0.0.3",
+          "from": "ps-tree@0.0.3",
           "dependencies": {
-            "keypress": {
-              "version": "0.1.0",
-              "from": "keypress@0.1.x"
+            "event-stream": {
+              "version": "0.5.3",
+              "from": "event-stream@~0.5",
+              "dependencies": {
+                "optimist": {
+                  "version": "0.2.8",
+                  "from": "optimist@0.2",
+                  "dependencies": {
+                    "wordwrap": {
+                      "version": "0.0.2",
+                      "from": "wordwrap@>=0.0.1 <0.1.0"
+                    }
+                  }
+                }
+              }
             }
           }
         }
       }
     },
-    "socket.io": {
-      "version": "0.9.16",
-      "from": "socket.io@0.9.x",
+    "npm": {
+      "version": "1.4.24",
+      "from": "npm@1.4.x",
       "dependencies": {
-        "socket.io-client": {
-          "version": "0.9.16",
-          "from": "socket.io-client@0.9.16",
-          "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz",
+        "abbrev": {
+          "version": "1.0.5",
+          "from": "abbrev@latest",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
+        },
+        "ansi": {
+          "version": "0.3.0",
+          "from": "ansi@latest",
+          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
+        },
+        "ansicolors": {
+          "version": "0.3.2",
+          "from": "ansicolors@latest"
+        },
+        "ansistyles": {
+          "version": "0.1.3",
+          "from": "ansistyles@0.1.3",
+          "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz"
+        },
+        "archy": {
+          "version": "0.0.2",
+          "from": "archy@0.0.2"
+        },
+        "block-stream": {
+          "version": "0.0.7",
+          "from": "block-stream@latest"
+        },
+        "char-spinner": {
+          "version": "1.0.1",
+          "from": "char-spinner@latest",
+          "resolved": "https://registry.npmjs.org/char-spinner/-/char-spinner-1.0.1.tgz"
+        },
+        "child-process-close": {
+          "version": "0.1.1",
+          "from": "child-process-close@",
+          "resolved": "https://registry.npmjs.org/child-process-close/-/child-process-close-0.1.1.tgz"
+        },
+        "chmodr": {
+          "version": "0.1.0",
+          "from": "chmodr@latest"
+        },
+        "chownr": {
+          "version": "0.0.1",
+          "from": "../chownr"
+        },
+        "cmd-shim": {
+          "version": "1.1.2",
+          "from": "cmd-shim@~1.1.1",
+          "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-1.1.2.tgz"
+        },
+        "columnify": {
+          "version": "1.1.0",
+          "from": "columnify@latest",
+          "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.1.0.tgz",
           "dependencies": {
-            "uglify-js": {
-              "version": "1.2.5",
-              "from": "uglify-js@1.2.5"
-            },
-            "ws": {
-              "version": "0.4.31",
-              "from": "ws@0.4.x",
+            "strip-ansi": {
+              "version": "0.2.2",
+              "from": "strip-ansi@^0.2.1",
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.2.2.tgz",
               "dependencies": {
-                "commander": {
-                  "version": "0.6.1",
-                  "from": "commander@~0.6.1"
-                },
-                "nan": {
-                  "version": "0.3.2",
-                  "from": "nan@~0.3.0"
-                },
-                "tinycolor": {
-                  "version": "0.0.1",
-                  "from": "tinycolor@0.x"
-                },
-                "options": {
-                  "version": "0.0.5",
-                  "from": "options@>=0.0.5"
+                "ansi-regex": {
+                  "version": "0.1.0",
+                  "from": "ansi-regex@^0.1.0",
+                  "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.1.0.tgz"
                 }
               }
             },
-            "xmlhttprequest": {
-              "version": "1.4.2",
-              "from": "xmlhttprequest@1.4.2"
-            },
-            "active-x-obfuscator": {
-              "version": "0.0.1",
-              "from": "active-x-obfuscator@0.0.1",
+            "wcwidth.js": {
+              "version": "0.0.4",
+              "from": "wcwidth.js@~0.0.4",
+              "resolved": "https://registry.npmjs.org/wcwidth.js/-/wcwidth.js-0.0.4.tgz",
               "dependencies": {
-                "zeparser": {
-                  "version": "0.0.5",
-                  "from": "zeparser@0.0.5"
+                "underscore": {
+                  "version": "1.6.0",
+                  "from": "underscore@>= 1.3.0",
+                  "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
                 }
               }
             }
           }
         },
-        "policyfile": {
-          "version": "0.0.4",
-          "from": "policyfile@0.0.4",
-          "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz"
-        },
-        "base64id": {
+        "editor": {
           "version": "0.1.0",
-          "from": "base64id@0.1.0"
+          "from": "editor@latest",
+          "resolved": "https://registry.npmjs.org/editor/-/editor-0.1.0.tgz"
         },
-        "redis": {
-          "version": "0.7.3",
-          "from": "redis@0.7.3",
-          "resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz"
-        }
-      }
-    },
-    "underscore": {
-      "version": "1.4.4",
-      "from": "underscore@1.4.x"
-    },
-    "winston": {
-      "version": "0.7.3",
-      "from": "winston@0.7.x",
-      "dependencies": {
-        "cycle": {
-          "version": "1.0.3",
-          "from": "cycle@1.0.x"
+        "fstream": {
+          "version": "1.0.0",
+          "from": "fstream@latest"
         },
-        "eyes": {
-          "version": "0.1.8",
-          "from": "eyes@0.1.x"
+        "fstream-npm": {
+          "version": "1.0.0",
+          "from": "fstream-npm@latest",
+          "dependencies": {
+            "fstream-ignore": {
+              "version": "1.0.1",
+              "from": "fstream-ignore@^1.0.0"
+            }
+          }
         },
-        "pkginfo": {
-          "version": "0.3.0",
-          "from": "pkginfo@0.3.x"
+        "github-url-from-git": {
+          "version": "1.3.0",
+          "from": "github-url-from-git@latest",
+          "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.3.0.tgz"
         },
-        "request": {
-          "version": "2.16.6",
-          "from": "request@2.16.x",
+        "github-url-from-username-repo": {
+          "version": "0.2.0",
+          "from": "github-url-from-username-repo@latest",
+          "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-0.2.0.tgz"
+        },
+        "glob": {
+          "version": "4.0.5",
+          "from": "glob@latest",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-4.0.5.tgz"
+        },
+        "graceful-fs": {
+          "version": "3.0.2",
+          "from": "graceful-fs@~3.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.2.tgz"
+        },
+        "inflight": {
+          "version": "1.0.1",
+          "from": "inflight@~1.0.1",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.1.tgz"
+        },
+        "ini": {
+          "version": "1.2.1",
+          "from": "ini@latest",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.2.1.tgz"
+        },
+        "init-package-json": {
+          "version": "1.0.0",
+          "from": "init-package-json@1.0.0",
+          "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.0.0.tgz",
           "dependencies": {
-            "form-data": {
-              "version": "0.0.10",
-              "from": "form-data@~0.0.3",
-              "dependencies": {
-                "combined-stream": {
-                  "version": "0.0.4",
-                  "from": "combined-stream@~0.0.4",
-                  "dependencies": {
-                    "delayed-stream": {
-                      "version": "0.0.5",
-                      "from": "delayed-stream@0.0.5"
-                    }
-                  }
-                }
-              }
-            },
-            "mime": {
-              "version": "1.2.11",
-              "from": "mime@~1.2.7"
-            },
-            "hawk": {
-              "version": "0.10.2",
-              "from": "hawk@~0.10.2",
-              "dependencies": {
-                "hoek": {
-                  "version": "0.7.6",
-                  "from": "hoek@0.7.x"
-                },
-                "boom": {
-                  "version": "0.3.8",
-                  "from": "boom@0.3.x"
-                },
-                "cryptiles": {
-                  "version": "0.1.3",
-                  "from": "cryptiles@0.1.x"
-                },
-                "sntp": {
-                  "version": "0.1.4",
-                  "from": "sntp@0.1.x"
-                }
-              }
-            },
-            "node-uuid": {
-              "version": "1.4.1",
-              "from": "node-uuid@~1.4.0"
-            },
-            "cookie-jar": {
-              "version": "0.2.0",
-              "from": "cookie-jar@~0.2.0"
-            },
-            "aws-sign": {
-              "version": "0.2.0",
-              "from": "aws-sign@~0.2.0"
-            },
-            "oauth-sign": {
-              "version": "0.2.0",
-              "from": "oauth-sign@~0.2.0"
-            },
-            "forever-agent": {
-              "version": "0.2.0",
-              "from": "forever-agent@~0.2.0"
-            },
-            "tunnel-agent": {
-              "version": "0.2.0",
-              "from": "tunnel-agent@~0.2.0"
-            },
-            "json-stringify-safe": {
-              "version": "3.0.0",
-              "from": "json-stringify-safe@~3.0.0"
-            },
-            "qs": {
-              "version": "0.5.6",
-              "from": "qs@~0.5.4"
+            "promzard": {
+              "version": "0.2.2",
+              "from": "promzard@~0.2.0",
+              "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.2.2.tgz"
+            }
+          }
+        },
+        "lockfile": {
+          "version": "0.4.2",
+          "from": "lockfile@0.4.2",
+          "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-0.4.2.tgz"
+        },
+        "lru-cache": {
+          "version": "2.5.0",
+          "from": "lru-cache@latest"
+        },
+        "minimatch": {
+          "version": "1.0.0",
+          "from": "minimatch@latest",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
+          "dependencies": {
+            "sigmund": {
+              "version": "1.0.0",
+              "from": "sigmund@~1.0.0",
+              "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz"
             }
           }
         },
-        "stack-trace": {
-          "version": "0.0.9",
-          "from": "stack-trace@0.0.x"
-        }
-      }
-    },
-    "xmla4js": {
-      "version": "0.0.2",
-      "from": "xmla4js@git://github.com/rpbouman/xmla4js.git",
-      "resolved": "git://github.com/rpbouman/xmla4js.git#40a0be2637c3f18c986d3e5cbe4c32cf8f995531"
-    },
-    "underscore.string": {
-      "version": "2.3.3",
-      "from": "underscore.string@~2.3.3"
-    },
-    "ursa": {
-      "version": "0.8.0",
-      "from": "ursa@0.8.x"
-    },
-    "xtuple-query": {
-      "version": "1.0.0",
-      "from": "xtuple-query@~1.0.0",
-      "dependencies": {
-        "congruence": {
-          "version": "1.2.3",
-          "from": "congruence@1.2.3",
-          "resolved": "https://registry.npmjs.org/congruence/-/congruence-1.2.3.tgz"
+        "mkdirp": {
+          "version": "0.5.0",
+          "from": "mkdirp@latest",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
+          "dependencies": {
+            "minimist": {
+              "version": "0.0.8",
+              "from": "minimist@0.0.8",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+            }
+          }
+        },
+        "node-gyp": {
+          "version": "1.0.1",
+          "from": "node-gyp@latest"
+        },
+        "nopt": {
+          "version": "3.0.1",
+          "from": "nopt@latest"
+        },
+        "npm-cache-filename": {
+          "version": "1.0.1",
+          "from": "npm-cache-filename@latest",
+          "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.1.tgz"
+        },
+        "npm-install-checks": {
+          "version": "1.0.2",
+          "from": "npm-install-checks@latest"
+        },
+        "npm-registry-client": {
+          "version": "2.0.4",
+          "from": "npm-registry-client@2.0.4",
+          "resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-2.0.4.tgz"
+        },
+        "npm-user-validate": {
+          "version": "0.1.0",
+          "from": "npm-user-validate@latest"
+        },
+        "npmconf": {
+          "version": "1.1.5",
+          "from": "npmconf@1.1.5",
+          "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-1.1.5.tgz",
+          "dependencies": {
+            "config-chain": {
+              "version": "1.1.8",
+              "from": "config-chain@~1.1.8",
+              "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.8.tgz",
+              "dependencies": {
+                "proto-list": {
+                  "version": "1.2.3",
+                  "from": "proto-list@~1.2.1",
+                  "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.3.tgz"
+                }
+              }
+            }
+          }
+        },
+        "npmlog": {
+          "version": "0.1.1",
+          "from": "npmlog@latest"
+        },
+        "once": {
+          "version": "1.3.0",
+          "from": "once@latest"
+        },
+        "opener": {
+          "version": "1.3.0",
+          "from": "opener@latest"
+        },
+        "osenv": {
+          "version": "0.1.0",
+          "from": "osenv@~0.1.0"
+        },
+        "path-is-inside": {
+          "version": "1.0.1",
+          "from": "path-is-inside@1.0.1",
+          "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz"
+        },
+        "read": {
+          "version": "1.0.5",
+          "from": "read@latest",
+          "dependencies": {
+            "mute-stream": {
+              "version": "0.0.4",
+              "from": "mute-stream@~0.0.4"
+            }
+          }
+        },
+        "read-installed": {
+          "version": "2.0.5",
+          "from": "read-installed@latest",
+          "dependencies": {
+            "util-extend": {
+              "version": "1.0.1",
+              "from": "util-extend@^1.0.1",
+              "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.1.tgz"
+            }
+          }
+        },
+        "read-package-json": {
+          "version": "1.2.6",
+          "from": "read-package-json@latest",
+          "dependencies": {
+            "normalize-package-data": {
+              "version": "1.0.0",
+              "from": "normalize-package-data@^1.0.0"
+            }
+          }
         },
-        "underscore": {
-          "version": "1.5.2",
-          "from": "underscore@~1.5.2"
-        }
-      }
-    },
-    "googleapis": {
-      "version": "0.4.7",
-      "from": "googleapis@~0.4.6",
-      "dependencies": {
         "request": {
-          "version": "2.25.0",
-          "from": "request@~2.25.0",
+          "version": "2.30.0",
+          "from": "request@latest",
           "dependencies": {
             "qs": {
               "version": "0.6.6",
               "from": "json-stringify-safe@~5.0.0"
             },
             "forever-agent": {
-              "version": "0.5.2",
+              "version": "0.5.0",
               "from": "forever-agent@~0.5.0"
             },
+            "node-uuid": {
+              "version": "1.4.1",
+              "from": "node-uuid@~1.4.0"
+            },
+            "mime": {
+              "version": "1.2.11",
+              "from": "mime@~1.2.9"
+            },
+            "tough-cookie": {
+              "version": "0.9.15",
+              "from": "tough-cookie@~0.9.15",
+              "dependencies": {
+                "punycode": {
+                  "version": "1.2.3",
+                  "from": "punycode@>=0.2.0"
+                }
+              }
+            },
+            "form-data": {
+              "version": "0.1.2",
+              "from": "form-data@~0.1.0",
+              "dependencies": {
+                "combined-stream": {
+                  "version": "0.0.4",
+                  "from": "combined-stream@~0.0.4",
+                  "dependencies": {
+                    "delayed-stream": {
+                      "version": "0.0.5",
+                      "from": "delayed-stream@0.0.5"
+                    }
+                  }
+                },
+                "async": {
+                  "version": "0.2.9",
+                  "from": "async@~0.2.9"
+                }
+              }
+            },
             "tunnel-agent": {
               "version": "0.3.0",
               "from": "tunnel-agent@~0.3.0"
                 }
               }
             },
+            "oauth-sign": {
+              "version": "0.3.0",
+              "from": "oauth-sign@~0.3.0"
+            },
             "hawk": {
               "version": "1.0.0",
               "from": "hawk@~1.0.0",
                 }
               }
             },
-            "aws-sign": {
-              "version": "0.3.0",
-              "from": "aws-sign@~0.3.0"
-            },
-            "oauth-sign": {
-              "version": "0.3.0",
-              "from": "oauth-sign@~0.3.0"
-            },
-            "cookie-jar": {
-              "version": "0.3.0",
-              "from": "cookie-jar@~0.3.0"
-            },
-            "node-uuid": {
-              "version": "1.4.1",
-              "from": "node-uuid@~1.4.0"
-            },
-            "mime": {
-              "version": "1.2.11",
-              "from": "mime@~1.2.9",
-              "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
-            },
-            "form-data": {
-              "version": "0.1.2",
-              "from": "form-data@~0.1.0",
-              "dependencies": {
-                "combined-stream": {
-                  "version": "0.0.4",
-                  "from": "combined-stream@~0.0.4",
-                  "dependencies": {
-                    "delayed-stream": {
-                      "version": "0.0.5",
-                      "from": "delayed-stream@0.0.5"
-                    }
-                  }
-                },
-                "async": {
-                  "version": "0.2.10",
-                  "from": "async@~0.2.9"
-                }
-              }
+            "aws-sign2": {
+              "version": "0.5.0",
+              "from": "aws-sign2@~0.5.0"
             }
           }
         },
-        "async": {
-          "version": "0.2.6",
-          "from": "async@0.2.6",
-          "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz"
+        "retry": {
+          "version": "0.6.0",
+          "from": "retry"
         },
-        "gapitoken": {
-          "version": "0.1.0",
-          "from": "gapitoken@0.1.0",
-          "resolved": "https://registry.npmjs.org/gapitoken/-/gapitoken-0.1.0.tgz",
+        "rimraf": {
+          "version": "2.2.8",
+          "from": "rimraf@latest",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
+        },
+        "semver": {
+          "version": "2.3.0",
+          "from": "semver@latest"
+        },
+        "sha": {
+          "version": "1.2.4",
+          "from": "sha@latest",
+          "resolved": "https://registry.npmjs.org/sha/-/sha-1.2.4.tgz",
           "dependencies": {
-            "jws": {
-              "version": "0.0.2",
-              "from": "jws@0.0.2",
+            "readable-stream": {
+              "version": "1.0.27-1",
+              "from": "readable-stream@1.0",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
               "dependencies": {
-                "tap": {
-                  "version": "0.3.3",
-                  "from": "tap@~0.3.3",
-                  "dependencies": {
-                    "inherits": {
-                      "version": "1.0.0"
-                    },
-                    "yamlish": {
-                      "version": "0.0.5"
-                    },
-                    "slide": {
-                      "version": "1.1.5",
-                      "from": "slide@*"
-                    },
-                    "runforcover": {
-                      "version": "0.0.2",
-                      "from": "runforcover@~0.0.2",
-                      "dependencies": {
-                        "bunker": {
-                          "version": "0.1.2",
-                          "from": "bunker@0.1.X",
-                          "dependencies": {
-                            "burrito": {
-                              "version": "0.2.12",
-                              "from": "burrito@>=0.2.5 <0.3",
-                              "dependencies": {
-                                "traverse": {
-                                  "version": "0.5.2",
-                                  "from": "traverse@~0.5.1"
-                                },
-                                "uglify-js": {
-                                  "version": "1.1.1",
-                                  "from": "uglify-js@~1.1.1"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "nopt": {
-                      "version": "2.2.1",
-                      "from": "nopt@~2",
-                      "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz",
-                      "dependencies": {
-                        "abbrev": {
-                          "version": "1.0.5",
-                          "from": "abbrev@1",
-                          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
-                        }
-                      }
-                    },
-                    "mkdirp": {
-                      "version": "0.3.5",
-                      "from": "mkdirp@~0.3"
-                    },
-                    "difflet": {
-                      "version": "0.2.6",
-                      "from": "difflet@~0.2.0",
-                      "dependencies": {
-                        "traverse": {
-                          "version": "0.6.6",
-                          "from": "traverse@0.6.x"
-                        },
-                        "charm": {
-                          "version": "0.1.2",
-                          "from": "charm@0.1.x"
-                        },
-                        "deep-is": {
-                          "version": "0.1.2",
-                          "from": "deep-is@0.1.x"
-                        }
-                      }
-                    },
-                    "deep-equal": {
-                      "version": "0.0.0",
-                      "from": "deep-equal@~0.0.0"
-                    },
-                    "buffer-equal": {
-                      "version": "0.0.0",
-                      "from": "buffer-equal@~0.0.0"
-                    }
-                  }
+                "core-util-is": {
+                  "version": "1.0.1",
+                  "from": "core-util-is@~1.0.0",
+                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                 },
-                "base64url": {
-                  "version": "0.0.3",
-                  "from": "base64url@0.0.3",
-                  "resolved": "https://registry.npmjs.org/base64url/-/base64url-0.0.3.tgz"
+                "isarray": {
+                  "version": "0.0.1",
+                  "from": "isarray@0.0.1",
+                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+                },
+                "string_decoder": {
+                  "version": "0.10.25-1",
+                  "from": "string_decoder@~0.10.x",
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.25-1.tgz"
                 }
               }
             }
           }
+        },
+        "slide": {
+          "version": "1.1.5",
+          "from": "slide@latest"
+        },
+        "sorted-object": {
+          "version": "1.0.0",
+          "from": "sorted-object@"
+        },
+        "tar": {
+          "version": "1.0.0",
+          "from": "tar@latest"
+        },
+        "text-table": {
+          "version": "0.2.0",
+          "from": "text-table@~0.2.0"
+        },
+        "uid-number": {
+          "version": "0.0.5",
+          "from": "uid-number@latest",
+          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz"
+        },
+        "which": {
+          "version": "1.0.5",
+          "from": "which@1"
+        },
+        "inherits": {
+          "version": "2.0.1",
+          "from": "inherits@"
         }
       }
     },
-    "chai": {
-      "version": "1.5.0",
-      "from": "chai@1.5.x"
-    },
-    "require-uncache": {
-      "version": "0.0.2",
-      "from": "require-uncache@0.0.x"
+    "oauth2orize": {
+      "version": "0.1.0",
+      "from": "oauth2orize@0.1.x",
+      "dependencies": {
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@0.7.x",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        }
+      }
     },
-    "csslint": {
-      "version": "0.10.0",
-      "from": "csslint@~0.10.0",
+    "oauth2orize-jwt-bearer": {
+      "version": "0.1.0",
+      "from": "oauth2orize-jwt-bearer@0.1.x",
       "dependencies": {
-        "parserlib": {
-          "version": "0.2.5",
-          "from": "parserlib@~0.2.2",
-          "resolved": "https://registry.npmjs.org/parserlib/-/parserlib-0.2.5.tgz"
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
         }
       }
     },
-    "mocha": {
-      "version": "1.9.0",
-      "from": "mocha@1.9.x",
+    "passport": {
+      "version": "0.1.18",
+      "from": "passport@0.1.x",
       "dependencies": {
-        "commander": {
-          "version": "0.6.1",
-          "from": "commander@0.6.1"
-        },
-        "growl": {
-          "version": "1.7.0",
-          "from": "growl@1.7.x"
-        },
-        "jade": {
-          "version": "0.26.3",
-          "from": "jade@0.26.3",
-          "dependencies": {
-            "mkdirp": {
-              "version": "0.3.0",
-              "from": "mkdirp@0.3.0",
-              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz"
-            }
-          }
-        },
-        "diff": {
-          "version": "1.0.2",
-          "from": "diff@1.0.2",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.2.tgz"
-        },
-        "debug": {
-          "version": "0.8.1",
-          "from": "debug@*",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz"
-        },
-        "mkdirp": {
-          "version": "0.3.3",
-          "from": "mkdirp@0.3.3",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.3.tgz"
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
         },
-        "ms": {
-          "version": "0.3.0",
-          "from": "ms@0.3.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.3.0.tgz"
+        "pause": {
+          "version": "0.0.1",
+          "from": "pause@0.0.1"
         }
       }
     },
-    "zombie": {
-      "version": "1.4.1",
-      "from": "zombie@1.4.x",
+    "passport-http": {
+      "version": "0.2.2",
+      "from": "passport-http@0.2.x",
       "dependencies": {
-        "eventsource": {
-          "version": "0.0.10",
-          "from": "eventsource@~0.0.5"
-        },
-        "jsdom": {
-          "version": "0.2.19",
-          "from": "jsdom@~0.2.15",
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
+        }
+      }
+    },
+    "passport-http-bearer": {
+      "version": "0.2.1",
+      "from": "passport-http-bearer@0.2.x",
+      "dependencies": {
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
+        }
+      }
+    },
+    "passport-local": {
+      "version": "0.1.6",
+      "from": "passport-local@0.1.x",
+      "dependencies": {
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
+        }
+      }
+    },
+    "passport-oauth2-client-password": {
+      "version": "0.1.1",
+      "from": "passport-oauth2-client-password@0.1.x",
+      "dependencies": {
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
+        }
+      }
+    },
+    "passport-oauth2-jwt-bearer": {
+      "version": "0.1.1",
+      "from": "passport-oauth2-jwt-bearer@0.1.x",
+      "dependencies": {
+        "pkginfo": {
+          "version": "0.2.3",
+          "from": "pkginfo@0.2.x"
+        }
+      }
+    },
+    "paynode": {
+      "version": "0.3.6",
+      "from": "paynode@0.3.6",
+      "dependencies": {
+        "braintree": {
+          "version": "1.17.0",
+          "from": "braintree@*",
+          "resolved": "https://registry.npmjs.org/braintree/-/braintree-1.17.0.tgz",
           "dependencies": {
-            "htmlparser": {
-              "version": "1.7.7",
-              "from": "htmlparser@1.x"
+            "dateformat": {
+              "version": "1.0.1-1.2.3",
+              "from": "dateformat@=1.0.1-1.2.3",
+              "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.1-1.2.3.tgz"
             },
-            "cssom": {
-              "version": "0.2.5",
-              "from": "cssom@0.2.x"
+            "semver": {
+              "version": "2.2.1",
+              "from": "semver@=2.2.1",
+              "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz"
             },
-            "cssstyle": {
-              "version": "0.2.11",
-              "from": "cssstyle@>=0.2.3",
+            "readable-stream": {
+              "version": "1.1.10",
+              "from": "readable-stream@=1.1.10",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.10.tgz",
               "dependencies": {
-                "cssom": {
-                  "version": "0.3.0",
-                  "from": "cssom@0.3.x"
+                "core-util-is": {
+                  "version": "1.0.1",
+                  "from": "core-util-is@~1.0.0"
+                },
+                "string_decoder": {
+                  "version": "0.10.31",
+                  "from": "string_decoder@~0.10.x",
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                },
+                "debuglog": {
+                  "version": "0.0.2",
+                  "from": "debuglog@0.0.2",
+                  "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-0.0.2.tgz"
                 }
               }
             },
-            "contextify": {
-              "version": "0.1.7",
-              "from": "contextify@0.1.x",
+            "underscore": {
+              "version": "1.3.1",
+              "from": "underscore@=1.3.1",
+              "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.3.1.tgz"
+            },
+            "xml2js": {
+              "version": "0.1.13",
+              "from": "xml2js@=0.1.13",
+              "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.1.13.tgz",
               "dependencies": {
-                "bindings": {
-                  "version": "1.2.0",
-                  "from": "bindings@*"
-                },
-                "nan": {
-                  "version": "0.8.0",
-                  "from": "nan@~0.8.0"
+                "sax": {
+                  "version": "0.6.0",
+                  "from": "sax@>=0.1.1"
                 }
               }
-            }
-          }
-        },
-        "mime": {
-          "version": "1.2.11",
-          "from": "mime@~1.2.7"
-        },
-        "ms": {
-          "version": "0.1.0",
-          "from": "ms@~0.1.0"
-        },
-        "q": {
-          "version": "0.8.12",
-          "from": "q@~0.8.6"
-        },
-        "request": {
-          "version": "2.10.0",
-          "from": "request@~2.10.0"
-        },
-        "tough-cookie": {
-          "version": "0.9.15",
-          "from": "tough-cookie@~0.9.13",
-          "dependencies": {
-            "punycode": {
-              "version": "1.2.4",
-              "from": "punycode@~1.2.3"
-            }
-          }
-        },
-        "ws": {
-          "version": "0.4.31",
-          "from": "ws@~0.4.21",
-          "dependencies": {
-            "commander": {
-              "version": "0.6.1",
-              "from": "commander@~0.6.1"
-            },
-            "nan": {
-              "version": "0.3.2",
-              "from": "nan@~0.3.0"
-            },
-            "tinycolor": {
-              "version": "0.0.1",
-              "from": "tinycolor@0.x"
             },
-            "options": {
-              "version": "0.0.5",
-              "from": "options@>=0.0.5"
+            "source-map-support": {
+              "version": "0.1.2",
+              "from": "source-map-support@=0.1.2",
+              "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.1.2.tgz",
+              "dependencies": {
+                "source-map": {
+                  "version": "0.1.8",
+                  "from": "source-map@0.1.8",
+                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.8.tgz",
+                  "dependencies": {
+                    "amdefine": {
+                      "version": "0.1.0",
+                      "from": "amdefine@>=0.0.4"
+                    }
+                  }
+                }
+              }
             }
           }
         }
       }
     },
-    "jshint": {
-      "version": "2.4.4",
-      "from": "jshint@2.4.x",
+    "pg": {
+      "version": "0.14.1",
+      "from": "pg@0.14.x",
+      "resolved": "https://registry.npmjs.org/pg/-/pg-0.14.1.tgz",
+      "dependencies": {
+        "generic-pool": {
+          "version": "2.0.4",
+          "from": "generic-pool@~2.0.2"
+        },
+        "deprecate": {
+          "version": "0.1.0",
+          "from": "deprecate@~0.1.0"
+        }
+      }
+    },
+    "request": {
+      "version": "2.14.0",
+      "from": "request@2.14.x",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.14.0.tgz",
       "dependencies": {
-        "shelljs": {
-          "version": "0.1.4",
-          "from": "shelljs@0.1.x"
-        },
-        "cli": {
-          "version": "0.4.5",
-          "from": "cli@0.4.x",
+        "form-data": {
+          "version": "0.0.7",
+          "from": "form-data@~0.0.3",
           "dependencies": {
-            "glob": {
-              "version": "3.2.9",
-              "from": "glob@>= 3.1.4",
+            "combined-stream": {
+              "version": "0.0.4",
+              "from": "combined-stream@~0.0.4",
               "dependencies": {
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@2"
+                "delayed-stream": {
+                  "version": "0.0.5",
+                  "from": "delayed-stream@0.0.5"
                 }
               }
+            },
+            "async": {
+              "version": "0.1.22",
+              "from": "async@~0.1.9"
             }
           }
         },
-        "minimatch": {
-          "version": "0.2.14",
-          "from": "minimatch@0.x.x",
+        "mime": {
+          "version": "1.2.9",
+          "from": "mime@~1.2.7"
+        }
+      }
+    },
+    "rimraf": {
+      "version": "2.2.8",
+      "from": "rimraf@2.2.x"
+    },
+    "rjson": {
+      "version": "0.2.4",
+      "from": "rjson@~0.2.4",
+      "dependencies": {
+        "commander": {
+          "version": "1.1.1",
+          "from": "commander@~1.1.1",
           "dependencies": {
-            "lru-cache": {
-              "version": "2.5.0",
-              "from": "lru-cache@2"
-            },
-            "sigmund": {
-              "version": "1.0.0",
-              "from": "sigmund@~1.0.0"
+            "keypress": {
+              "version": "0.1.0",
+              "from": "keypress@0.1.x"
             }
           }
-        },
-        "htmlparser2": {
-          "version": "3.3.0",
-          "from": "htmlparser2@3.3.x",
+        }
+      }
+    },
+    "socket.io": {
+      "version": "0.9.17",
+      "from": "socket.io@0.9.x",
+      "dependencies": {
+        "socket.io-client": {
+          "version": "0.9.16",
+          "from": "socket.io-client@0.9.16",
+          "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz",
           "dependencies": {
-            "domhandler": {
-              "version": "2.1.0",
-              "from": "domhandler@2.1"
-            },
-            "domutils": {
-              "version": "1.1.6",
-              "from": "domutils@1.1"
-            },
-            "domelementtype": {
-              "version": "1.1.1",
-              "from": "domelementtype@1"
+            "uglify-js": {
+              "version": "1.2.5",
+              "from": "uglify-js@1.2.5",
+              "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz"
             },
-            "readable-stream": {
-              "version": "1.0.27-1",
-              "from": "readable-stream@1.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
+            "ws": {
+              "version": "0.4.32",
+              "from": "ws@0.4.x",
               "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@~1.0.0"
+                "commander": {
+                  "version": "2.1.0",
+                  "from": "commander@~2.1.0",
+                  "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz"
                 },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+                "nan": {
+                  "version": "1.0.0",
+                  "from": "nan@~1.0.0"
                 },
-                "string_decoder": {
-                  "version": "0.10.25-1",
-                  "from": "string_decoder@~0.10.x"
+                "tinycolor": {
+                  "version": "0.0.1",
+                  "from": "tinycolor@0.x"
                 },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@~2.0.1"
+                "options": {
+                  "version": "0.0.5",
+                  "from": "options@>=0.0.5"
+                }
+              }
+            },
+            "xmlhttprequest": {
+              "version": "1.4.2",
+              "from": "xmlhttprequest@1.4.2",
+              "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz"
+            },
+            "active-x-obfuscator": {
+              "version": "0.0.1",
+              "from": "active-x-obfuscator@0.0.1",
+              "dependencies": {
+                "zeparser": {
+                  "version": "0.0.5",
+                  "from": "zeparser@0.0.5"
                 }
               }
             }
           }
         },
-        "console-browserify": {
-          "version": "0.1.6",
-          "from": "console-browserify@0.1.x"
+        "policyfile": {
+          "version": "0.0.4",
+          "from": "policyfile@0.0.4",
+          "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz"
         },
-        "exit": {
-          "version": "0.1.2",
-          "from": "exit@0.1.x"
+        "base64id": {
+          "version": "0.1.0",
+          "from": "base64id@0.1.0"
+        },
+        "redis": {
+          "version": "0.7.3",
+          "from": "redis@0.7.3",
+          "resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz"
         }
       }
     },
-    "html5": {
-      "version": "0.3.13",
-      "from": "html5@0.3.13",
+    "underscore": {
+      "version": "1.4.4",
+      "from": "underscore@1.4.x",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz"
+    },
+    "underscore.string": {
+      "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",
       "dependencies": {
-        "jsdom": {
-          "version": "0.10.5",
-          "from": "jsdom@>= 0.6.0",
+        "cycle": {
+          "version": "1.0.3",
+          "from": "cycle@1.0.x"
+        },
+        "eyes": {
+          "version": "0.1.8",
+          "from": "eyes@0.1.x"
+        },
+        "pkginfo": {
+          "version": "0.3.0",
+          "from": "pkginfo@0.3.x",
+          "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.0.tgz"
+        },
+        "request": {
+          "version": "2.16.6",
+          "from": "request@2.16.x",
           "dependencies": {
-            "htmlparser2": {
-              "version": "3.7.1",
-              "from": "htmlparser2@>= 3.1.5 <4",
+            "form-data": {
+              "version": "0.0.10",
+              "from": "form-data@~0.0.3",
               "dependencies": {
-                "domhandler": {
-                  "version": "2.2.0",
-                  "from": "domhandler@2.2"
-                },
-                "domutils": {
-                  "version": "1.4.3",
-                  "from": "domutils@1.4"
-                },
-                "domelementtype": {
-                  "version": "1.1.1",
-                  "from": "domelementtype@1"
-                },
-                "readable-stream": {
-                  "version": "1.1.13-1",
-                  "from": "readable-stream@1.1",
-                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13-1.tgz",
+                "combined-stream": {
+                  "version": "0.0.5",
+                  "from": "combined-stream@~0.0.4",
+                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.5.tgz",
                   "dependencies": {
-                    "core-util-is": {
-                      "version": "1.0.1",
-                      "from": "core-util-is@~1.0.0"
-                    },
-                    "isarray": {
-                      "version": "0.0.1",
-                      "from": "isarray@0.0.1",
-                      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                    },
-                    "string_decoder": {
-                      "version": "0.10.25-1",
-                      "from": "string_decoder@~0.10.x"
-                    },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@~2.0.1"
+                    "delayed-stream": {
+                      "version": "0.0.5",
+                      "from": "delayed-stream@0.0.5",
+                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
                     }
                   }
+                }
+              }
+            },
+            "mime": {
+              "version": "1.2.11",
+              "from": "mime@~1.2.7"
+            },
+            "hawk": {
+              "version": "0.10.2",
+              "from": "hawk@~0.10.2",
+              "dependencies": {
+                "hoek": {
+                  "version": "0.7.6",
+                  "from": "hoek@0.7.x"
                 },
-                "entities": {
-                  "version": "1.0.0",
-                  "from": "entities@1.0"
+                "boom": {
+                  "version": "0.3.8",
+                  "from": "boom@0.3.x"
+                },
+                "cryptiles": {
+                  "version": "0.1.3",
+                  "from": "cryptiles@0.1.x"
+                },
+                "sntp": {
+                  "version": "0.1.4",
+                  "from": "sntp@0.1.x"
                 }
               }
             },
-            "nwmatcher": {
-              "version": "1.3.3",
-              "from": "nwmatcher@~1.3.2"
+            "node-uuid": {
+              "version": "1.4.1",
+              "from": "node-uuid@~1.4.0"
+            },
+            "cookie-jar": {
+              "version": "0.2.0",
+              "from": "cookie-jar@~0.2.0"
+            },
+            "aws-sign": {
+              "version": "0.2.0",
+              "from": "aws-sign@~0.2.0",
+              "resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.2.0.tgz"
+            },
+            "oauth-sign": {
+              "version": "0.2.0",
+              "from": "oauth-sign@~0.2.0"
+            },
+            "forever-agent": {
+              "version": "0.2.0",
+              "from": "forever-agent@~0.2.0"
             },
-            "xmlhttprequest": {
-              "version": "1.6.0",
-              "from": "xmlhttprequest@>=1.5.0"
+            "tunnel-agent": {
+              "version": "0.2.0",
+              "from": "tunnel-agent@~0.2.0"
             },
-            "cssom": {
-              "version": "0.3.0",
-              "from": "cssom@~0.3.0"
+            "json-stringify-safe": {
+              "version": "3.0.0",
+              "from": "json-stringify-safe@~3.0.0"
             },
-            "cssstyle": {
-              "version": "0.2.11",
-              "from": "cssstyle@~0.2.9"
+            "qs": {
+              "version": "0.5.6",
+              "from": "qs@~0.5.4"
+            }
+          }
+        },
+        "stack-trace": {
+          "version": "0.0.9",
+          "from": "stack-trace@0.0.x"
+        }
+      }
+    },
+    "xtuple-linguist": {
+      "version": "0.1.0",
+      "from": "xtuple-linguist@0.1.x"
+    },
+    "xtuple-query": {
+      "version": "1.0.2",
+      "from": "xtuple-query@~1.0.0",
+      "dependencies": {
+        "congruence": {
+          "version": "1.2.4",
+          "from": "congruence@1.2.4",
+          "resolved": "https://registry.npmjs.org/congruence/-/congruence-1.2.4.tgz",
+          "dependencies": {
+            "moment": {
+              "version": "2.4.0",
+              "from": "moment@2.4.0",
+              "resolved": "https://registry.npmjs.org/moment/-/moment-2.4.0.tgz"
             },
-            "contextify": {
-              "version": "0.1.7",
-              "from": "contextify@~0.1.5",
-              "dependencies": {
-                "bindings": {
-                  "version": "1.2.0",
-                  "from": "bindings@*"
-                },
-                "nan": {
-                  "version": "0.8.0",
-                  "from": "nan@~0.8.0"
-                }
-              }
+            "underscore": {
+              "version": "1.5.2",
+              "from": "underscore@1.5.2"
             }
           }
         },
-        "opts": {
-          "version": "1.2.2",
-          "from": "opts@~1.2.1"
+        "moment": {
+          "version": "2.6.0",
+          "from": "moment@2.6.0",
+          "resolved": "https://registry.npmjs.org/moment/-/moment-2.6.0.tgz"
         },
-        "html5-entities": {
-          "version": "0.5.1",
-          "from": "html5-entities@~0.5.0"
+        "underscore": {
+          "version": "1.6.0",
+          "from": "underscore@1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
         }
       }
     },
-    "nodemon": {
-      "version": "1.0.17",
-      "from": "nodemon@~1.0.15",
+    "zombie": {
+      "version": "1.4.1",
+      "from": "zombie@1.4.x",
+      "resolved": "https://registry.npmjs.org/zombie/-/zombie-1.4.1.tgz",
       "dependencies": {
-        "update-notifier": {
-          "version": "0.1.8",
-          "from": "update-notifier@~0.1.7",
+        "eventsource": {
+          "version": "0.0.10",
+          "from": "eventsource@~0.0.5",
+          "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.0.10.tgz"
+        },
+        "jsdom": {
+          "version": "0.2.19",
+          "from": "jsdom@~0.2.15",
+          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-0.2.19.tgz",
           "dependencies": {
-            "request": {
-              "version": "2.27.0",
-              "from": "request@~2.27.0",
-              "dependencies": {
-                "qs": {
-                  "version": "0.6.6",
-                  "from": "qs@~0.6.0"
-                },
-                "json-stringify-safe": {
-                  "version": "5.0.0",
-                  "from": "json-stringify-safe@~5.0.0"
-                },
-                "forever-agent": {
-                  "version": "0.5.2",
-                  "from": "forever-agent@~0.5.0"
-                },
-                "tunnel-agent": {
-                  "version": "0.3.0",
-                  "from": "tunnel-agent@~0.3.0"
-                },
-                "http-signature": {
-                  "version": "0.10.0",
-                  "from": "http-signature@~0.10.0",
-                  "dependencies": {
-                    "assert-plus": {
-                      "version": "0.1.2",
-                      "from": "assert-plus@0.1.2"
-                    },
-                    "asn1": {
-                      "version": "0.1.11",
-                      "from": "asn1@0.1.11"
-                    },
-                    "ctype": {
-                      "version": "0.5.2",
-                      "from": "ctype@0.5.2"
-                    }
-                  }
-                },
-                "hawk": {
-                  "version": "1.0.0",
-                  "from": "hawk@~1.0.0",
-                  "dependencies": {
-                    "hoek": {
-                      "version": "0.9.1",
-                      "from": "hoek@0.9.x"
-                    },
-                    "boom": {
-                      "version": "0.4.2",
-                      "from": "boom@0.4.x"
-                    },
-                    "cryptiles": {
-                      "version": "0.2.2",
-                      "from": "cryptiles@0.2.x"
-                    },
-                    "sntp": {
-                      "version": "0.2.4",
-                      "from": "sntp@0.2.x"
-                    }
-                  }
-                },
-                "aws-sign": {
-                  "version": "0.3.0",
-                  "from": "aws-sign@~0.3.0"
-                },
-                "oauth-sign": {
-                  "version": "0.3.0",
-                  "from": "oauth-sign@~0.3.0"
-                },
-                "cookie-jar": {
-                  "version": "0.3.0",
-                  "from": "cookie-jar@~0.3.0"
-                },
-                "node-uuid": {
-                  "version": "1.4.1",
-                  "from": "node-uuid@~1.4.0"
-                },
-                "mime": {
-                  "version": "1.2.11",
-                  "from": "mime@~1.2.9",
-                  "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
-                },
-                "form-data": {
-                  "version": "0.1.2",
-                  "from": "form-data@~0.1.0",
-                  "dependencies": {
-                    "combined-stream": {
-                      "version": "0.0.4",
-                      "from": "combined-stream@~0.0.4",
-                      "dependencies": {
-                        "delayed-stream": {
-                          "version": "0.0.5",
-                          "from": "delayed-stream@0.0.5"
-                        }
-                      }
-                    }
-                  }
-                }
-              }
+            "htmlparser": {
+              "version": "1.7.7",
+              "from": "htmlparser@1.x"
             },
-            "configstore": {
-              "version": "0.2.3",
-              "from": "configstore@~0.2.2",
+            "cssom": {
+              "version": "0.2.5",
+              "from": "cssom@0.2.x"
+            },
+            "cssstyle": {
+              "version": "0.2.14",
+              "from": "cssstyle@>=0.2.3",
               "dependencies": {
-                "mkdirp": {
-                  "version": "0.3.5",
-                  "from": "mkdirp@~0.3.5"
-                },
-                "js-yaml": {
-                  "version": "3.0.2",
-                  "from": "js-yaml@~3.0.1",
-                  "dependencies": {
-                    "argparse": {
-                      "version": "0.1.15",
-                      "from": "argparse@~ 0.1.11"
-                    },
-                    "esprima": {
-                      "version": "1.0.4",
-                      "from": "esprima@~ 1.0.2"
-                    }
-                  }
-                },
-                "osenv": {
-                  "version": "0.0.3",
-                  "from": "osenv@0.0.3",
-                  "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz"
-                },
-                "graceful-fs": {
-                  "version": "2.0.3",
-                  "from": "graceful-fs@~2.0.1"
-                },
-                "uuid": {
-                  "version": "1.4.1",
-                  "from": "uuid@~1.4.1"
-                },
-                "object-assign": {
-                  "version": "0.1.2",
-                  "from": "object-assign@~0.1.1"
+                "cssom": {
+                  "version": "0.3.0",
+                  "from": "cssom@0.3.x"
                 }
               }
             },
-            "semver": {
-              "version": "2.1.0",
-              "from": "semver@~2.1.0"
-            },
-            "chalk": {
-              "version": "0.4.0",
-              "from": "chalk@~0.4.0",
+            "contextify": {
+              "version": "0.1.8",
+              "from": "contextify@0.1.x",
               "dependencies": {
-                "has-color": {
-                  "version": "0.1.7",
-                  "from": "has-color@~0.1.0",
-                  "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz"
+                "bindings": {
+                  "version": "1.2.1",
+                  "from": "bindings@*",
+                  "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
                 },
-                "ansi-styles": {
+                "nan": {
                   "version": "1.0.0",
-                  "from": "ansi-styles@~1.0.0"
-                },
-                "strip-ansi": {
-                  "version": "0.1.1",
-                  "from": "strip-ansi@~0.1.0"
+                  "from": "nan@~1.0.0"
                 }
               }
             }
           }
         },
-        "minimatch": {
-          "version": "0.2.14",
-          "from": "minimatch@~0.2.14",
+        "mime": {
+          "version": "1.2.11",
+          "from": "mime@~1.2.7"
+        },
+        "ms": {
+          "version": "0.1.0",
+          "from": "ms@~0.1.0"
+        },
+        "q": {
+          "version": "0.8.12",
+          "from": "q@~0.8.6",
+          "resolved": "https://registry.npmjs.org/q/-/q-0.8.12.tgz"
+        },
+        "request": {
+          "version": "2.10.0",
+          "from": "request@~2.10.0"
+        },
+        "tough-cookie": {
+          "version": "0.9.15",
+          "from": "tough-cookie@~0.9.13",
           "dependencies": {
-            "lru-cache": {
-              "version": "2.5.0",
-              "from": "lru-cache@2"
+            "punycode": {
+              "version": "1.3.1",
+              "from": "punycode@>=0.2.0",
+              "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.1.tgz"
+            }
+          }
+        },
+        "ws": {
+          "version": "0.4.32",
+          "from": "ws@~0.4.21",
+          "dependencies": {
+            "commander": {
+              "version": "2.1.0",
+              "from": "commander@~2.1.0",
+              "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz"
             },
-            "sigmund": {
+            "nan": {
               "version": "1.0.0",
-              "from": "sigmund@~1.0.0"
+              "from": "nan@~1.0.0"
+            },
+            "tinycolor": {
+              "version": "0.0.1",
+              "from": "tinycolor@0.x"
+            },
+            "options": {
+              "version": "0.0.5",
+              "from": "options@>=0.0.5"
             }
           }
         }
index 75ea3d8..fe76483 100644 (file)
@@ -2,7 +2,7 @@
   "author": "xTuple <dev@xtuple.com>",
   "name": "xtuple",
   "description": "xTuple Enterprise Resource Planning Mobile-Web client",
-  "version": "4.5.0",
+  "version": "4.7.0-beta",
   "repository": {
     "type": "git",
     "url": "https://github.com/xtuple/xtuple.git"
@@ -24,6 +24,7 @@
     "less": "1.5.0",
     "moment": "2.4.x",
     "nodemailer": "0.3.x",
+    "npm":"1.4.x",
     "node-forge": "0.6.x",
     "oauth2orize": "0.1.x",
     "oauth2orize-jwt-bearer": "0.1.x",
     "underscore": "1.4.x",
     "winston": "0.7.x",
     "underscore.string": "~2.3.3",
-    "ursa":"0.8.x"
+    "ursa": "0.8.x",
+    "xtuple-linguist": "0.1.x",
+    "jquery": "~2.1.1"
   },
   "devDependencies": {
     "chai": "1.5.x",
-    "jshint": "2.4.x",
     "mocha": "1.9.x",
-    "require-uncache": "0.0.x",
     "html5": "0.3.13",
+    "jshint": "2.4.x",
     "zombie": "1.4.x",
-    "csslint": "~0.10.0",
-    "nodemon": "~1.0.15"
+    "nodemon": "~1.0.15",
+    "csslint": "~0.10.0"
   },
   "optionalDependencies": {
     "xtuple-query": "~1.0.0",
     "googleapis": "~0.4.6"
   },
   "engines": {
-    "node": "0.8.x"
+    "node": "^0.10"
   },
   "main": "node-datasource/main.js",
   "scripts": {
@@ -68,6 +70,8 @@
     "build-basic-postbooks-demo": "./scripts/build_app.js -d postbooks_demo --databaseonly -e foundation-database -i -s foundation-database/postbooks_demo_data.sql",
     "build-basic-quickstart": "./scripts/build_app.js -d quickstart --databaseonly -e foundation-database -i -s foundation-database/quickstart_data.sql",
     "jshint": "./node_modules/.bin/jshint --exclude node-datasource/lib/query/node_modules lib/backbone-x/source lib/enyo-x/source lib/tools/source enyo-client/application/source/ enyo-client/extensions node-datasource",
+    "jsdoc-api": "rm -rf scripts/output;./node_modules/xtuple-documentation/node_modules/jsdoc/jsdoc -t ./node_modules/xtuple-documentation/jsdoc-setup/api-templates -c ./node_modules/xtuple-documentation/jsdoc-setup/jsdoc.conf.json -d ./scripts/output -r ./lib/backbone-x/source ./lib/tools/source ./lib/enyo-x/source/widgets ./lib/enyo-x/source/views ./lib/enyo-x/source/app.js ./lib/enyo-x/source/core.js ./node_modules/xtuple-documentation/jsdoc-setup/api-readme.md",
+    "jsdoc-specs": "rm -rf scripts/output/*;mkdir scripts/output/tech-specs;./node_modules/xtuple-documentation/node_modules/jsdoc/jsdoc -t ./node_modules/xtuple-documentation/jsdoc-setup/spec-templates -c ./node_modules/xtuple-documentation/jsdoc-setup/jsdoc.conf.json -d ./scripts/output/tech-specs/ -r ./test/specs ./node_modules/xtuple-documentation/jsdoc-setup/tech-specs-readme.md;mkdir scripts/output/user-specs;./node_modules/xtuple-documentation/node_modules/jsdoc/jsdoc -t ./node_modules/xtuple-documentation/jsdoc-setup/spec-templates -c ./node_modules/xtuple-documentation/jsdoc-setup/jsdoc-user.conf.json -d ./scripts/output/user-specs/ -r ./test/specs ./node_modules/xtuple-documentation/jsdoc-setup/user-specs-readme.md;",
     "preinstall": "cd node-datasource/lib/query ; npm install",
     "start": "node_modules/.bin/nodemon node-datasource/main.js --debug --watch node-datasource",
     "test-build": "./node_modules/.bin/mocha -R spec test/build/build_app.js",
diff --git a/scripts/GENERATE_SPECS_README.md b/scripts/GENERATE_SPECS_README.md
deleted file mode 100644 (file)
index 8ce90fa..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Specs are generated by running files in the `test/specs` folder through a special template.
-
-Create the specs by running
-``` bash
-cd scripts
-./generateSpecs.sh
-```
-
-### Two templates
-
-Two different specs will be created, one for technical users and one for end users, in the
-`jsdoc/outspecuser` and `jsdoc/outspec` folders, respectively. You can follow these conventions
-to have the same source generate different verbiage:
-
-In a property description, any text in square brackets `[Hello, techies!]` will only be visible to technical
-users. Text in parens `(Hello, men-on-street!)` will only be visible to end users. Anything written without
-either delimiter will be visible to both users.
-
-An empty pair of parens `()` means: don't show this property at all to end users.
-
-TODO: make the end user documentation automatically pull up translated labels instead of property names
-for the properties
-
-### Other conventions
-
-For non-property tags, you can associate a tag with a subgrouping using the @member option. `@member -`
-is shorthand for `@member Other`. These groupings will automatically be sorted according to a pre-determined
-order, as defined at the top of `scripts/templates/xtuple_specs/tmpl/container.tmpl`. Feel free to add to 
-this list.
index 72b9bb8..f15d6ef 100755 (executable)
@@ -23,6 +23,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     .option('-f, --frozen', 'Apply frozen scripts for first-time foundation extension installs.')
     .option('-i, --initialize', 'Initialize database. Must be used with the -b or -s flag.')
     .option('-k, --keepsql', 'Do not delete the temporary sql files that represent the payload of the build.')
+    .option('-p, --populate', 'Populate data.')
     .option('-q, --quick', 'Quicken install by not dropping the views pre-emptively.')
     .option('-s, --source [/path/to/source_data.sql]', 'Location of source data. Must be used with the -i flag.')
     .option('-u, --unregister', 'Unregister an extension.')
@@ -38,6 +39,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     frozen: program.frozen,
     initialize: program.initialize,
     keepSql: program.keepsql,
+    populateData: program.populate,
     source: program.source,
     unregister: program.unregister,
     wipeViews: !program.quick && !program.extension,
index 62ee937..12fa090 100755 (executable)
@@ -15,19 +15,16 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
   var fs = require("fs"),
     program = require("commander"),
     path = require("path"),
-    buildDatabaseUtil = require("./lib/build_database_util");
+    explodeManifest = require("./lib/util/process_manifest").explodeManifest;
 
   program
     .option('-m, --manifest [/path/to/manifest.js]', 'Location of manifest file.')
     .option('-n, --name [inventory_upgrade.sql]', 'Name of destination file.')
     .parse(process.argv);
 
-  // the path is not relative if it starts with a slash
-  var manifestPath = program.manifest.substring(0, 1) === '/' ?
-    program.manifest :
-    path.join(process.cwd(), program.manifest);
+  var manifestFilename = path.resolve(process.cwd(), program.manifest);
 
-  buildDatabaseUtil.explodeManifest(manifestPath, {}, function (err, contents) {
+  explodeManifest({manifestFilename: manifestFilename}, function (err, contents) {
     var outputFile;
     if (err) {
       console.log("error: ", err);
diff --git a/scripts/generateDocs.sh b/scripts/generateDocs.sh
deleted file mode 100755 (executable)
index f4928b6..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-rm -rf ../../jsdoc/out
-../../jsdoc/jsdoc -t ./templates/xtuple -c ./jsdoc.conf.json -d ../../jsdoc/out -r ../lib/backbone-x/source ../lib/tools/source ../lib/enyo-x/source/widgets ../lib/enyo-x/source/views ../lib/enyo-x/source/app.js ../lib/enyo-x/source/core.js ./jsdoc_README.md
diff --git a/scripts/generateSpecs.sh b/scripts/generateSpecs.sh
deleted file mode 100755 (executable)
index 71799a7..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-rm -rf ../../jsdoc/outspecsuser
-../../jsdoc/jsdoc -t ./templates/xtuple_specs -c ./jsdoc-user.conf.json -d ../../jsdoc/outspecsuser ../test/specs ./jsdoc_spec_user_README.md
-rm -rf ../../jsdoc/outspecs
-../../jsdoc/jsdoc -t ./templates/xtuple_specs -c ./jsdoc.conf.json -d ../../jsdoc/outspecs ../test/specs ./jsdoc_spec_README.md
diff --git a/scripts/install_bi.sh b/scripts/install_bi.sh
deleted file mode 100755 (executable)
index ebb9291..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-#!/bin/sh
-RUN_DIR=$(pwd)
-LOG_FILE=$RUN_DIR/install_bi.log
-mv $LOG_FILE $LOG_FILE.old
-log() {
-       echo $@
-       echo $@ >> $LOG_FILE
-}
-
-varlog() {
-       log $(eval "echo $1 = \$$1")
-}
-
-cdir() {
-       cd $1
-       log "Changing directory to $1"
-}
-
-RUNALL=true
-BI_DIR=$RUN_DIR/../../bi
-PRIVATE_DIR=$RUN_DIR/../../private-extensions
-XT_DIR=$RUN_DIR/..
-export BISERVER_HOME=$RUN_DIR/../../ErpBI
-DATABASE=dev
-DATABASEHOST=localhost
-DATABASEUSER=admin
-DATABASEPASSWORD=admin
-DATABASEPORT=5432
-DATABASELOADPORT=5432
-DATABASESSL=
-TENANT=default
-CITIES=democities.txt
-COMMONNAME=$(hostname)
-CREATE=Y
-INCREMENTAL=N
-
-while getopts ":ieblmuxyd:U:g:P:t:n:j:z:h:p:c:o:r:k:" opt; do
-  case $opt in
-    e)
-      # Install ErpBI and configure
-      RUNALL=
-      DOWNLOAD=true
-      ;;
-    b)
-      # Build BI solution and install
-      RUNALL=
-      RUN=true
-      ;;
-    l)
-      # Extract and load analytic data into erpbi database
-      RUNALL=
-      LOAD=true
-      ;;
-    m)
-      # Prep the Mobile Client to connect to BI Server
-      RUNALL=
-      PREP=true
-      ;;
-    d)
-      # Set database name (for extract)
-      DATABASE=$OPTARG
-      ;;
-    p)
-      # Set database port for extract)
-      DATABASEPORT=$OPTARG
-      ;;
-    h)
-      # Set database host name (for extract)
-      DATABASEHOST=$OPTARG
-      ;;
-    U)
-      # Set database user name (for extract)
-      DATABASEUSER=$OPTARG
-      ;;
-    P)
-      # Set database user password (for extract)
-      DATABASEPASSWORD=$OPTARG
-      ;;
-    o)
-      # Set database port (for load)
-      DATABASELOADPORT=$OPTARG
-      ;;         
-    y)
-      # Set database ssl connect option (for extract)
-      DATABASESSL="?ssl=true\&sslfactory=org.postgresql.ssl.NonValidatingFactory"
-      ;;
-    k)
-      # Server key file for SSL
-      SSLKEY=$OPTARG
-      ;;
-    r)
-      # Server certificate file for SSL
-      SSLCERT=$OPTARG
-      ;;         
-    t)
-      # Set tenant name
-      TENANT=$OPTARG
-      ;;
-    g)
-      # Geographic data file
-      CITIES=$OPTARG
-      ;;         
-    n)
-      # Common name for self signed SSL certificate
-      COMMONNAME=$OPTARG
-      ;;
-    c)
-      # Path for config file
-      CONFIGPATH=$OPTARG
-      ;;
-    u)
-      # Incremental updates
-      INCREMENTAL=Y
-      ;;
-    j)
-      # Java home
-      export JAVA_HOME=$OPTARG
-      ;;
-    x)
-      # Do not create erpbi database schema
-      CREATE=N
-      ;;
-    z)
-      # ErpBI.zip path
-      export ERPBIPATH=$OPTARG
-      ;;  
-    \?)
-      log "Invalid option: -"$OPTARG
-      exit 1
-      ;;
-    :)
-      log "Option -"$OPTARG" requires an argument."
-      exit 1
-      ;;
-  esac
-done
-
-if [ $RUNALL ]
-then
-       DOWNLOAD=true
-       RUN=true
-       LOAD=true
-       PREP=true
-fi
-
-if  [ "$INCREMENTAL" = "Y" ]
-then
-       CREATE=N
-fi
-
-if  ! test -d $BI_DIR ;
-then
-       log ""
-       log "#############################################################"
-    log "Sorry bi folder not found.  You must clone xtuple/bi"
-       log "#############################################################"
-       log ""
-    exit 1
-fi
-
-if  [ $ERPBIPATH ]
-then
-       if   ! test -f $ERPBIPATH  
-       then
-               log ""
-               log "####################################################################################"
-               log "Sorry can't find ErpBI.zip at "$ERPBIPATH
-               log "####################################################################################"
-               log ""
-               exit 1
-       fi
-fi
-
-if  [ $CONFIGPATH ]
-then
-       if   ! test -f $CONFIGPATH  
-       then
-               log ""
-               log "####################################################################################"
-               log "Sorry can't find config file at "$CONFIGPATH
-               log "####################################################################################"
-               log ""
-               exit 1
-       fi
-else
-       CONFIGPATH=config.js
-fi
-
-if   ! test -d $PRIVATE_DIR && $RUNALL   
-then
-       log ""
-       log "####################################################################################"
-    log "Sorry private-extensions folder not found.  You must clone xtuple/private-extensions"
-       log "####################################################################################"
-       log ""
-    exit 1
-fi
-
-if  [ $SSLKEY ]
-then
-       if  ! [ $SSLCERT ]
-       then
-               log ""
-               log "####################################################################################"
-               log "Sorry if SSL Key is specified, SSL certificate must be specified."
-               log "####################################################################################"
-               log ""
-               exit 1
-       fi
-fi
-
-if  [ $SSLCERT ]
-then
-       if  ! [ $SSLKEY ]
-       then
-               log ""
-               log "####################################################################################"
-               log "Sorry if SSL certificate is specified, the SSL key must be specified."
-               log "####################################################################################"
-               log ""
-               exit 1
-       fi
-fi
-
-install_packages () {
-       log ""
-       log "######################################################"
-       log "Install prereqs."
-       log "######################################################"
-       log ""
-       apt-get install -qy git openjdk-6-jdk maven2
-       export JAVA_HOME=$(readlink -f /usr/bin/javac | sed "s:bin/javac::")    
-       if  ! test -e $JAVA_HOME/bin/javac ;
-       then
-               log ""
-               log "#############################################################"
-               log "Sorry can not find javac.  Set Java Home with the -j argument"
-               log "#############################################################"
-               log ""
-               exit 1
-       fi
-}
-
-download_files () {
-       log ""
-       log "######################################################"
-       log "Download ErpBI, set permissions and generate keystore "
-       log "and truststore for SSL with self signed cert using    "
-       log "common name "$COMMONNAME
-       log "######################################################"
-       log ""
-
-       rm -R ../../ErpBI       
-       if  [ $ERPBIPATH ]
-       then
-               log ""
-               log "######################################################"
-               log "Unzipping "$ERPBIPATH
-               log "######################################################"
-               log ""
-               unzip -q $ERPBIPATH -d ../..
-       else
-               rm ../../ErpBI.zip
-               wget http://sourceforge.net/projects/erpbi/files/candidate-release/ErpBI.zip/download -O ../../ErpBI.zip
-               log ""
-               log "######################################################"
-               log "Unzipping ErpBI.zip"
-               log "######################################################"
-               log ""
-               unzip -q ../../ErpBI.zip -d ../..
-       fi              
-
-       cdir $BISERVER_HOME/biserver-ce/
-       chmod 755 -R . 2>&1 | tee -a $LOG_FILE
-       
-       if  [ $SSLKEY ]
-       then
-               cp $SSLKEY $BISERVER_HOME/biserver-ce/ssl-keys
-               cp $SSLCERT $BISERVER_HOME/biserver-ce/ssl-keys
-               cdir $BISERVER_HOME/biserver-ce/ssl-keys
-               rm cacerts.jks
-               rm keystore_server.jks
-               rm server.cer
-               openssl pkcs12 -export -out server.pkcs12 -in $SSLCERT -inkey $SSLKEY -passout pass:changeit
-               keytool -importkeystore -srcstorepass changeit -deststorepass changeit -srckeystore server.pkcs12 -srcstoretype PKCS12 -destkeystore keystore_server.jks -deststoretype JKS 
-               keytool -export -alias 1 -file $SSLCERT -storepass changeit -keystore keystore_server.jks
-               keytool -import -alias 1 -v -trustcacerts -file $SSLCERT -keypass changeit -storepass changeit -keystore cacerts.jks -noprompt  
-       else
-               cdir $BISERVER_HOME/biserver-ce/ssl-keys
-               rm cacerts.jks
-               rm keystore_server.jks
-               rm server.cer
-               keytool -genkey -alias tomcat -keyalg RSA -keypass changeit -storepass changeit -keystore keystore_server.jks -dname "cn="$COMMONNAME", ou=xTuple, o=xTuple, c=US"
-               keytool -export -alias tomcat -file server.cer -storepass changeit -keystore keystore_server.jks
-               keytool -import -alias tomcat -v -trustcacerts -file server.cer -keypass changeit -storepass changeit -keystore cacerts.jks -noprompt   
-       fi
-       
-       cdir $BISERVER_HOME/biserver-ce/tomcat/conf/Catalina/localhost
-       mv pentaho.xml pentaho.xml.sample
-       cat pentaho.xml.sample | \
-       sed s/org.h2.Driver/org.postgresql.Driver/ | \
-       sed s#jdbc:h2:../../../h2database/demomfg#jdbc:postgresql://localhost:5432/erpbi# \
-       > pentaho.xml  2>&1 | tee -a $LOG_FILE
-}
-
-run_scripts() {
-       log ""
-       log "######################################################"
-       log "Build BI solution and move to ErpBI at:               "
-       log $BISERVER_HOME
-       log "######################################################"
-       log ""
-       cdir $BI_DIR/olap-schema
-       mvn install 2>&1 | tee -a $LOG_FILE
-       java -jar Saxon-HE-9.4.jar -s:src/erpi-tenant-xtuple.xml -xsl:style.xsl -o:target/erpi-schema.xml
-       mvn process-resources 2>&1 | tee -a $LOG_FILE
-
-       cdir ../pentaho-extensions/oauthsso
-       mvn clean 2>&1 | tee -a $LOG_FILE
-       mvn install 2>&1 | tee -a $LOG_FILE
-       mvn process-resources 2>&1 | tee -a $LOG_FILE
-
-       cdir ../dynschema
-       mvn install 2>&1 | tee -a $LOG_FILE
-       mvn process-resources 2>&1 | tee -a $LOG_FILE
-       
-       cdir ../utils
-       mvn install 2>&1 | tee -a $LOG_FILE
-       mvn process-resources 2>&1 | tee -a $LOG_FILE
-
-       cdir ../../etl
-       mvn install 2>&1 | tee -a $LOG_FILE
-       mvn process-resources 2>&1 | tee -a $LOG_FILE
-}
-
-load_pentaho() {
-       log ""
-       log "######################################################"
-       log "Extract data from "$DATABASE" on host "$DATABASEHOST 
-       log "and load data into erpbi with tenant name " $TENANT
-       log "######################################################"
-       log ""
-       createdb -U postgres -O admin erpbi 2>&1 | tee -a $LOG_FILE
-       cdir $BISERVER_HOME/data-integration
-       export KETTLE_HOME=properties/psg-linux
-       
-       mv $KETTLE_HOME/.kettle/kettle.properties $KETTLE_HOME/.kettle/kettle.properties.sample  2>&1 | tee -a $LOG_FILE
-       cat $KETTLE_HOME/.kettle/kettle.properties.sample | \
-       sed s'#erpi.source.url=.*#erpi.source.url=jdbc\:postgresql\://'$DATABASEHOST'\:'$DATABASEPORT'/'$DATABASE$DATABASESSL'#' | \
-       sed s'#erpi.source.user=.*#erpi.source.user='$DATABASEUSER'#' | \
-       sed s'#erpi.source.password.*#erpi.source.password='$DATABASEPASSWORD'#' | \
-       sed s'#erpi.datamart.port.*#erpi.datamart.port='$DATABASELOADPORT'#' | \
-       sed s'#erpi.datamart.url=.*#erpi.datamart.url=jdbc\:postgresql\://localhost\:'$DATABASELOADPORT'/erpbi#' | \
-       sed s'#erpi.cities.file.*#erpi.cities.file='$CITIES'#' | \
-       sed s'#erpi.tenant.id=.*#erpi.tenant.id='$TENANT'.'$DATABASE'#' | \
-       sed s'#erpi.datamart.create=.*#erpi.datamart.create='$CREATE'#' | \
-       sed s'#erpi.incremental=.*#erpi.incremental='$INCREMENTAL'#' \
-       > $KETTLE_HOME/.kettle/kettle.properties  2>&1 | tee -a $LOG_FILE
-       
-       sh kitchenkh.sh -file=../ErpBI/ETL/JOBS/Load.kjb -level=Basic
-}
-
-prep_mobile() {
-       log ""
-       log "######################################################"
-       log "Prepare mobile app to use the BI Server. Create keys  "
-    log "for REST api used by single sign on.  Update config.js"
-    log "with BI Server URL https://"$COMMONNAME":8443"
-       log "######################################################"
-       log ""
-       if [ ! -d $XT_DIR/node-datasource/lib/rest-keys ]
-    then
-      mkdir $XT_DIR/node-datasource/lib/rest-keys
-    fi
-       cdir $XT_DIR/node-datasource/lib/rest-keys
-       openssl genrsa -out server.key 1024 2>&1 | tee -a $LOG_FILE
-       openssl rsa -in server.key -pubout > server.pub 2>&1 | tee -a $LOG_FILE
-       
-       #
-       # Would be better to get multiline sed working to put commonname in:
-       # biserver: {
-       #    hostname: myname
-       #
-       # Something similar to:
-       #       sed 'N;s#biServer: {\n        hostname:.*#biServer: {\n        hostname: \"'$COMMONNAME'\",#' \
-       
-       cdir $XT_DIR/node-datasource
-       mv $CONFIGPATH $CONFIGPATH'.old' 2>&1 | tee -a $LOG_FILE
-       cat $CONFIGPATH'.old' | \
-       sed 's#restkeyfile: .*#restkeyfile: \"./lib/rest-keys/server.key\",#' | \
-       sed 's#tenantname: .*#tenantname: \"'$TENANT'",#' | \
-       sed 's#bihost: .*#bihost: \"'$COMMONNAME'\",#' \
-       > $CONFIGPATH
-}
-
-install_packages
-
-if [ $? -ne 0 ]
-then
-       log "bad."
-fi
-
-if [ $DOWNLOAD ]
-then
-       download_files
-fi
-
-if [ $RUN ]
-then
-       run_scripts
-fi
-
-if [ $LOAD ]
-then
-       load_pentaho
-fi
-
-if [ $PREP ]
-then
-       prep_mobile
-fi
-
-log ""
-log "######################################################"
-log "                FINISED! READ ME                      "
-log "If you use the self signed certificate created by this"
-log "script you will need to accept the certificate in your"
-log "browser.  Connect to https://"$COMMONNAME":8443"
-log "######################################################"
-log ""
index d168eee..ee2121b 100644 (file)
@@ -23,7 +23,7 @@ sudo apt-get -q -y install \
   python-software-properties \
   software-properties-common
 
-NODE_VERSION=0.8.26
+NODE_VERSION=0.10.31
 
 DEBDIST=`lsb_release -c -s`
 echo "Trying to install xTuple for platform ${DEBDIST}"
@@ -153,6 +153,8 @@ install_packages() {
   sudo nvm alias default $NODE_VERSION
   sudo nvm alias xtuple $NODE_VERSION
 
+  # use latest npm
+  npm install -fg npm@1.4.25
        # npm no longer supports its self-signed certificates
        log "telling npm to use known registrars..."
        npm config set ca ""
@@ -224,6 +226,8 @@ init_everythings() {
        cdir $XT_DIR/node-datasource/lib/private
        cat /dev/urandom | tr -dc '0-9a-zA-Z!@#$%^&*_+-'| head -c 64 > salt.txt
        log "Created salt"
+       cat /dev/urandom | tr -dc '0-9a-zA-Z!@#$%^&*_+-'| head -c 64 > encryption_key.txt
+       log "Created encryption key"
        openssl genrsa -des3 -out server.key -passout pass:xtuple 1024 2>&1 | tee -a $LOG_FILE
        openssl rsa -in server.key -passin pass:xtuple -out key.pem -passout pass:xtuple 2>&1 | tee -a $LOG_FILE
        openssl req -batch -new -key key.pem -out server.csr -subj '/CN='$(hostname) 2>&1 | tee -a $LOG_FILE
diff --git a/scripts/jsdoc-user.conf.json b/scripts/jsdoc-user.conf.json
deleted file mode 100644 (file)
index 86ac71d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "tags": {
-        "allowUnknownTags": true
-    },
-    "source": {
-        "includePattern": ".+\\.js(doc)?$",
-        "excludePattern": "(^|\\/|\\\\)_"
-    },
-    "plugins": [],
-    "templates": {
-        "cleverLinks": false,
-        "monospaceLinks": false,
-        "endUser": true,
-        "default": {
-            "outputSourceFiles": true
-        }
-    }
-}
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
deleted file mode 100644 (file)
index b01736e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "tags": {
-        "allowUnknownTags": true
-    },
-    "source": {
-        "includePattern": ".+\\.js(doc)?$",
-        "excludePattern": "(^|\\/|\\\\)_"
-    },
-    "plugins": [],
-    "templates": {
-        "cleverLinks": false,
-        "monospaceLinks": false,
-        "default": {
-            "outputSourceFiles": true
-        }
-    }
-}
diff --git a/scripts/jsdoc_README.md b/scripts/jsdoc_README.md
deleted file mode 100644 (file)
index 175bd55..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-This is the API documentation for the framework code on
-the client of the xTuple Web/Mobile platform. It does not
-include database or datasource code, nor does it include
-business-object-specific implementation classes.
-
-These objects are in one of three namespaces:
-
-* `XV`: views, typically defined in `lib/enyo-x`
-* `XM`: models, typically defined in `lib/backbone-x`
-* `XT`: tools, typically defined in `lib/tools`
-
-You can see a filtered list of the objects by namespace
-by clicking on the namespace links at the bottom of the
-sidebar.
-
-See our [architectual overview](https://github.com/xtuple/xtuple/wiki/Overview)
-for a more detailed description.
diff --git a/scripts/jsdoc_spec_README.md b/scripts/jsdoc_spec_README.md
deleted file mode 100644 (file)
index d688a1f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Specifications for xTuple business objects, as generated by our testing framework.
-
-Click on a business object on the right to see the technical specifications
-of that object and other related objects.
diff --git a/scripts/jsdoc_spec_user_README.md b/scripts/jsdoc_spec_user_README.md
deleted file mode 100644 (file)
index 8fb774d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Specifications for xTuple business objects, as generated by our testing framework.
-
-Click on a business object on the right to see and end-user description of that object and other related objects.
index 4ddeca2..469fbd6 100644 (file)
@@ -5,13 +5,17 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
 var _ = require('underscore'),
   async = require('async'),
   buildDatabase = require("./build_database"),
-  buildDatabaseUtil = require("./build_database_util"),
+  buildDictionary = require("./build_dictionary"),
   buildClient = require("./build_client").buildClient,
+  defaultExtensions = require("./util/default_extensions").extensions,
   dataSource = require('../../node-datasource/lib/ext/datasource').dataSource,
   exec = require('child_process').exec,
   fs = require('fs'),
+  initDatabase = require("./util/init_database").initDatabase,
+  inspectDatabaseExtensions = require("./util/inspect_database").inspectDatabaseExtensions,
+  npm = require('npm'),
   path = require('path'),
-  unregister = buildDatabaseUtil.unregister,
+  unregister = require("./util/unregister").unregister,
   winston = require('winston');
 
 /*
@@ -30,117 +34,122 @@ var _ = require('underscore'),
 
   var creds;
 
+  var buildAll = function (specs, creds, buildAllCallback) {
+    async.series([
+      function (done) {
+        // step 0: init the database, if requested
 
-  exports.build = function (options, callback) {
-    var buildSpecs = {},
-      databases = [],
-      extension,
-      //
-      // Looks in a database to see which extensions are registered, and
-      // tacks onto that list the core directories.
-      //
-      getRegisteredExtensions = function (database, callback) {
-        var result,
-          credsClone = JSON.parse(JSON.stringify(creds)),
-          existsSql = "select relname from pg_class where relname = 'ext'",
-          preInstallSql = "select xt.js_init();update xt.ext set ext_location = '/core-extensions' " +
-            "where ext_name = 'oauth2' and ext_location = '/xtuple-extensions';",
-          extSql = preInstallSql + "SELECT * FROM xt.ext ORDER BY ext_load_order",
-          defaultExtensions = [
-            { ext_location: '/core-extensions', ext_name: 'crm' },
-            { ext_location: '/core-extensions', ext_name: 'project' },
-            { ext_location: '/core-extensions', ext_name: 'sales' },
-            { ext_location: '/core-extensions', ext_name: 'billing' },
-            { ext_location: '/core-extensions', ext_name: 'purchasing' },
-            { ext_location: '/core-extensions', ext_name: 'oauth2' }
-          ],
-          adaptExtensions = function (err, res) {
-            if (err) {
-              callback(err);
-              return;
-            }
-
-            var paths = _.map(_.compact(res.rows), function (row) {
-              var location = row.ext_location,
-                name = row.ext_name,
-                extPath;
-
-              if (location === '/core-extensions') {
-                extPath = path.join(__dirname, "/../../enyo-client/extensions/source/", name);
-              } else if (location === '/xtuple-extensions') {
-                extPath = path.join(__dirname, "../../../xtuple-extensions/source", name);
-              } else if (location === '/private-extensions') {
-                extPath = path.join(__dirname, "../../../private-extensions/source", name);
-              }
-              return extPath;
-            });
+        if (specs.length === 1 &&
+            specs[0].initialize &&
+            (specs[0].backup || specs[0].source)) {
 
-            paths.unshift(path.join(__dirname, "../../enyo-client")); // core path
-            paths.unshift(path.join(__dirname, "../../lib/orm")); // lib path
-            paths.unshift(path.join(__dirname, "../../foundation-database")); // foundation path
-            callback(null, {
-              extensions: _.compact(paths),
-              database: database,
-              keepSql: options.keepSql,
-              wipeViews: options.wipeViews,
-              clientOnly: options.clientOnly,
-              databaseOnly: options.databaseOnly
-            });
-          };
+          // The user wants to initialize the database first (i.e. Step 0)
+          // Do that, then call this function again
+          initDatabase(specs[0], creds, function (err, res) {
+            specs[0].wasInitialized = true;
+            done(err, res);
+          });
+          return;
+        } else {
+          done();
+        }
 
-        credsClone.database = database;
-        dataSource.query(existsSql, credsClone, function (err, res) {
+      },
+      function (done) {
+        // step 1: npm install extension if necessary
+        // an alternate approach would be only npm install these
+        // extensions on an npm install.
+        var allExtensions = _.reduce(specs, function (memo, spec) {
+          memo.push(spec.extensions);
+          return _.flatten(memo);
+        }, []);
+        var npmExtensions = _.filter(allExtensions, function (extName) {
+          return extName && extName.indexOf("node_modules") >= 0;
+        });
+        if (npmExtensions.length === 0) {
+          done();
+          return;
+        }
+        npm.load(function (err, res) {
           if (err) {
-            callback(err);
+            done(err);
             return;
           }
-          if (res.rowCount === 0) {
-            // xt.ext doesn't exist, because this is probably a brand-new DB.
-            // No problem! Give them the core extensions.
-            adaptExtensions(null, { rows: defaultExtensions });
-          } else {
-            dataSource.query(extSql, credsClone, adaptExtensions);
-          }
+          npm.on("log", function (message) {
+            // log the progress of the installation
+            console.log(message);
+          });
+          async.map(npmExtensions, function (extName, next) {
+            npm.commands.install([path.basename(extName)], next);
+          }, done);
         });
       },
-      buildAll = function (specs, creds, buildAllCallback) {
-        buildClient(specs, function (err, res) {
-          if (err) {
-            buildAllCallback(err);
+      function (done) {
+        // step 2: build the client
+        buildClient(specs, done);
+      },
+      function (done) {
+        // step 3: build the database
+        buildDatabase.buildDatabase(specs, creds, function (databaseErr, databaseRes) {
+          if (databaseErr) {
+            buildAllCallback(databaseErr);
             return;
           }
-          buildDatabase.buildDatabase(specs, creds, function (databaseErr, databaseRes) {
-            var returnMessage;
-            if (databaseErr && (specs[0].wipeViews || specs[0].initialize)) {
-              buildAllCallback(databaseErr);
-              return;
-
-            } else if (databaseErr) {
-              buildAllCallback("Build failed. Try wiping the views next time by running me without the -q flag.");
-              return;
-            }
-            returnMessage = "\n";
-            _.each(specs, function (spec) {
-              returnMessage += "Database: " + spec.database + '\nDirectories:\n';
-              _.each(spec.extensions, function (ext) {
-                returnMessage += '  ' + ext + '\n';
-              });
+          var returnMessage = "\n";
+          _.each(specs, function (spec) {
+            returnMessage += "Database: " + spec.database + '\nDirectories:\n';
+            _.each(spec.extensions, function (ext) {
+              returnMessage += '  ' + ext + '\n';
             });
-            buildAllCallback(null, "Build succeeded." + returnMessage);
+          });
+          done(null, "Build succeeded." + returnMessage);
+        });
+      },
+      function (done) {
+        // step 4: import all dictionary files
+        if (specs[0].clientOnly || specs[0].databaseOnly) {
+          // don't build dictionaries if the user doesn't want us to
+          console.log("Not importing the dictionaries");
+          return done();
+        }
+        var databases = _.map(specs, function (spec) {
+          return spec.database;
+        });
+        async.map(databases, buildDictionary.importAllDictionaries, done);
+      }
+    ], function (err, results) {
+      buildAllCallback(err, results && results[results.length - 2]);
+    });
+  };
+
+  exports.build = function (options, callback) {
+    var buildSpecs = {},
+      databases = [],
+      extension,
+      getRegisteredExtensions = function (database, callback) {
+        var credsClone = JSON.parse(JSON.stringify(creds));
+        credsClone.database = database;
+        inspectDatabaseExtensions(credsClone, function (err, paths) {
+          callback(null, {
+            extensions: paths,
+            database: database,
+            keepSql: options.keepSql,
+            populateData: options.populateData,
+            wipeViews: options.wipeViews,
+            clientOnly: options.clientOnly,
+            databaseOnly: options.databaseOnly
           });
         });
       },
       config;
 
-    // the config path is not relative if it starts with a slash
-    if (options.config && options.config.substring(0, 1) === '/') {
-      config = require(options.config);
-    } else if (options.config) {
-      config = require(path.join(process.cwd(), options.config));
+    if (options.config) {
+      config = require(path.resolve(process.cwd(), options.config));
     } else {
-      config = require(path.join(__dirname, "../../node-datasource/config.js"));
+      config = require(path.resolve(__dirname, "../../node-datasource/config.js"));
     }
     creds = config.databaseServer;
+    creds.encryptionKeyFile = config.datasource.encryptionKeyFile;
     creds.host = creds.hostname; // adapt our lingo to node-postgres lingo
     creds.username = creds.user; // adapt our lingo to orm installer lingo
 
@@ -159,6 +168,9 @@ var _ = require('underscore'),
     } else if (options.backup && options.source) {
       callback("You can build from backup or from source but not both.");
 
+    } else if (options.backup && options.extension) {
+      callback("When you're building from a backup you get whatever extensions the backup merits.");
+
     } else if (options.initialize &&
         (options.backup || options.source) &&
         options.database &&
@@ -169,35 +181,24 @@ var _ = require('underscore'),
 
       buildSpecs.database = options.database;
       if (options.backup) {
-        // the backup path is not relative if it starts with a slash
-        buildSpecs.backup = options.backup.substring(0, 1) === '/' ?
-          options.backup :
-          path.join(process.cwd(), options.backup);
+        buildSpecs.backup = path.resolve(process.cwd(), options.backup);
+        buildSpecs.extensions = false;
+        // we'll determine the extensions by looking at the db after restore
       }
       if (options.source) {
-        // the source path is not relative if it starts with a slash
-        buildSpecs.source = options.source.substring(0, 1) === '/' ?
-          options.source :
-          path.join(process.cwd(), options.source);
+        buildSpecs.source = path.resolve(process.cwd(), options.source);
+        // if we initialize with the foundation, that means we want
+        // an unmobilized build
+        buildSpecs.extensions = options.extension ?
+          [options.extension] :
+          defaultExtensions;
       }
       buildSpecs.initialize = true;
       buildSpecs.keepSql = options.keepSql;
+      buildSpecs.populateData = options.populateData;
       buildSpecs.wipeViews = options.wipeViews;
       buildSpecs.clientOnly = options.clientOnly;
       buildSpecs.databaseOnly = options.databaseOnly;
-      // if we initialize with the foundation, that means we want
-      // an unmobilized build
-      buildSpecs.extensions = options.extension ? [options.extension] : [
-        path.join(__dirname, '../../foundation-database'),
-        path.join(__dirname, '../../lib/orm'),
-        path.join(__dirname, '../../enyo-client'),
-        path.join(__dirname, '../../enyo-client/extensions/source/crm'),
-        path.join(__dirname, '../../enyo-client/extensions/source/project'),
-        path.join(__dirname, '../../enyo-client/extensions/source/sales'),
-        path.join(__dirname, '../../enyo-client/extensions/source/billing'),
-        path.join(__dirname, '../../enyo-client/extensions/source/purchasing'),
-        path.join(__dirname, '../../enyo-client/extensions/source/oauth2')
-      ];
       buildAll([buildSpecs], creds, callback);
 
     } else if (options.initialize || options.backup || options.source) {
@@ -209,14 +210,12 @@ var _ = require('underscore'),
       // the user has specified an extension to build or unregister
       // extensions are assumed to be specified relative to the cwd
       buildSpecs = _.map(databases, function (database) {
-        // the extension is not relative if it starts with a slash
-        var extension = options.extension.substring(0, 1) === '/' ?
-          options.extension :
-          path.join(process.cwd(), options.extension);
+        var extension = path.resolve(process.cwd(), options.extension);
         return {
           database: database,
           frozen: options.frozen,
           keepSql: options.keepSql,
+          populateData: options.populateData,
           wipeViews: options.wipeViews,
           clientOnly: options.clientOnly,
           databaseOnly: options.databaseOnly,
index 7fe466a..adcf21d 100755 (executable)
@@ -10,9 +10,6 @@ var _ = require('underscore'),
   path = require('path'),
   rimraf = require('rimraf');
 
-  // TODO: relax the assumption that extension builds are js only (i.e. allow extension css)
-  // TODO: right now we just give the latest versions available in the db. This might possibly change.
-
 (function () {
   "use strict";
 
@@ -24,6 +21,9 @@ var _ = require('underscore'),
   exports.getClientSql = function (extPath, callback) {
     var extName,
       constructQuery = function (contents, extension, version, language) {
+        if (!contents || contents === "undefined") {
+          return "";
+        }
         return "select xt.js_init();select xt.insert_client($$" + contents +
           "$$, '" + extension +
           "', '" + version +
@@ -35,7 +35,7 @@ var _ = require('underscore'),
       callback(null, "");
       return;
 
-    } else if (extPath.indexOf("extensions") < 0) {
+    } else if (extPath.indexOf("extensions") < 0 && extPath.indexOf("node_modules") < 0) {
       // this is the core app, which has a slightly different process.
       fs.readFile(path.join(__dirname, "build/core.js"), "utf8", function (err, jsCode) {
         if (err) {
@@ -61,7 +61,7 @@ var _ = require('underscore'),
 
     } else {
       extName = path.basename(extPath).replace(/\/$/, ""); // the name of the extension
-      fs.readFile(path.join(__dirname, "build", extName + ".js"), "utf8", function (err, code) {
+      fs.readFile(path.join(__dirname, "build", extName + ".js"), "utf8", function (err, jsCode) {
         if (err) {
           if (err.code === 'ENOENT') {
             // it's not necessarily an error if there's no code here.
@@ -72,27 +72,19 @@ var _ = require('underscore'),
           callback(err);
           return;
         }
-        // get the extension version from the database manifest file
-        fs.readFile(path.join(extPath, "database/source/manifest.js"), "utf8", function (err, manifestContents) {
-          if (err) {
-            callback(err);
-            return;
+        fs.readFile(path.join(__dirname, "build", extName + ".css"), "utf8", function (err, cssCode) {
+          var version;
+          if (fs.existsSync(path.resolve(extPath, "package.json"))) {
+            version = require(path.resolve(extPath, "package.json")).version;
+          } else {
+            version = JSON.parse(fs.readFileSync(path.resolve(extPath, "database/source/manifest.js"))).version;
           }
-          var manifestDetails = JSON.parse(manifestContents);
-          if (!manifestDetails.version) {
+          if (!version) {
             // if the extensions don't declare their version, default to the package version
-            fs.readFile(path.join(__dirname, "../../package.json"), "utf8", function (err, packageJson) {
-              if (err) {
-                callback(err);
-                return;
-              }
-              var packageDetails = JSON.parse(packageJson);
-              callback(null, constructQuery(code, extName, packageDetails.version, "js"));
-            });
-
-          } else {
-            callback(null, constructQuery(code, extName, manifestDetails.version, "js"));
+            version = require(path.resolve(__dirname, "../../package.json")).version;
           }
+          callback(null, constructQuery(cssCode, extName, version, "css") +
+            constructQuery(jsCode, extName, version, "js"));
         });
       });
     }
@@ -104,6 +96,7 @@ var _ = require('underscore'),
   var buildExtension = function (extPath, callback) {
     // regex: remove trailing slash
     var extName = path.basename(extPath).replace(/\/$/, ""), // the name of the extension
+      cssFilename = extName + ".css",
       jsFilename = extName + ".js";
 
     // create the package file for enyo to use
@@ -114,7 +107,7 @@ var _ = require('underscore'),
         return;
       }
       // run the enyo deployment method asyncronously
-      var rootDir = path.join(extPath, "../..");
+      var rootDir = path.join(extPath, extPath.indexOf("node_modules") >= 0 ? "../../enyo-client/extensions/" : "../..");
       // we run the command from /scripts/lib, so that is where build directories and other
       // temp files are going to go.
       console.log("building " + extName);
@@ -130,9 +123,11 @@ var _ = require('underscore'),
           }
           // rename the file with the name of the extension so that we won't need to recreate it
           // in the case of multiple databases wanting the same client code
-          fs.rename(path.join(__dirname, "build/app.js"), path.join(__dirname, "build", jsFilename), function (err) {
-            callback(err);
-          });
+          fs.renameSync(path.join(__dirname, "build/app.js"), path.join(__dirname, "build", jsFilename));
+          if (fs.existsSync(path.join(__dirname, "build/app.css"))) {
+            fs.renameSync(path.join(__dirname, "build/app.css"), path.join(__dirname, "build", cssFilename));
+          }
+          callback();
         }
       );
     });
@@ -212,19 +207,21 @@ var _ = require('underscore'),
   };
 
   var build = function (extPath, callback) {
+    var isNodeModule = extPath.indexOf("node_modules") >= 0;
+
     if (extPath.indexOf("/lib/orm") >= 0 || extPath.indexOf("foundation-database") >= 0) {
       // There is nothing here to install on the client.
       callback();
       return;
     }
 
-    if (extPath.indexOf("extensions") < 0) {
+    if (extPath.indexOf("extensions") < 0 && !isNodeModule) {
       // this is the core app, which has a different deploy process.
       buildCore(callback);
       return;
     }
 
-    var enyoDir = path.join(extPath, "../../enyo");
+    var enyoDir = path.join(extPath, isNodeModule ? "../../enyo-client/extensions/enyo" : "../../enyo");
     fs.exists(path.join(extPath, "client"), function (exists) {
       if (!exists) {
         console.log(extPath + " has no client code. Not trying to build it.");
index f7f8934..6f64695 100644 (file)
@@ -6,8 +6,8 @@ _ = require('underscore');
 
 var  async = require('async'),
   dataSource = require('../../node-datasource/lib/ext/datasource').dataSource,
-  buildDatabaseUtil = require('./build_database_util'),
   exec = require('child_process').exec,
+  explodeManifest = require("./util/process_manifest").explodeManifest,
   fs = require('fs'),
   ormInstaller = require('./orm'),
   dictionaryBuilder = require('./build_dictionary'),
@@ -15,6 +15,7 @@ var  async = require('async'),
   path = require('path'),
   pg = require('pg'),
   os = require('os'),
+  sendToDatabase = require("./util/send_to_database").sendToDatabase,
   winston = require('winston');
 
 (function () {
@@ -44,29 +45,6 @@ var  async = require('async'),
         host: 'localhost' }
   */
   var buildDatabase = exports.buildDatabase = function (specs, creds, masterCallback) {
-    if (specs.length === 1 &&
-        specs[0].initialize &&
-        (specs[0].backup || specs[0].source)) {
-
-      // The user wants to initialize the database first (i.e. Step 0)
-      // Do that, then call this function again
-      buildDatabaseUtil.initDatabase(specs[0], creds, function (err, res) {
-        if (err) {
-          winston.error("Init database error: ", err);
-          masterCallback(err);
-          return;
-        }
-        // recurse to do the build step. Of course we don't want to initialize a second
-        // time, so destroy those flags.
-        specs[0].initialize = false;
-        specs[0].wasInitialized = true;
-        specs[0].backup = undefined;
-        specs[0].source = undefined;
-        buildDatabase(specs, creds, masterCallback);
-      });
-      return;
-    }
-
     //
     // The function to generate all the scripts for a database
     //
@@ -82,7 +60,6 @@ var  async = require('async'),
           extensionCallback(null, "");
           return;
         }
-        //winston.info("Installing extension", databaseName, extension);
         // deal with directory structure quirks
         var baseName = path.basename(extension),
           isFoundation = extension.indexOf("foundation-database") >= 0,
@@ -96,24 +73,30 @@ var  async = require('async'),
             extension.indexOf("extension") >= 0,
           isPublicExtension = extension.indexOf("xtuple-extensions") >= 0,
           isPrivateExtension = extension.indexOf("private-extensions") >= 0,
+          isNpmExtension = baseName.indexOf("xtuple-") >= 0,
+          isExtension = !isFoundation && !isLibOrm && !isApplicationCore,
           dbSourceRoot = (isFoundation || isFoundationExtension) ? extension :
             isLibOrm ? path.join(extension, "source") :
             path.join(extension, "database/source"),
           manifestOptions = {
+            manifestFilename: path.resolve(dbSourceRoot, "manifest.js"),
+            extensionPath: isExtension ?
+              path.resolve(dbSourceRoot, "../../") :
+              undefined,
             useFrozenScripts: spec.frozen,
             useFoundationScripts: baseName.indexOf('inventory') >= 0 ||
               baseName.indexOf('manufacturing') >= 0 ||
               baseName.indexOf('distribution') >= 0,
-            registerExtension: !isFoundation && !isLibOrm && !isApplicationCore,
+            registerExtension: isExtension,
             runJsInit: !isFoundation && !isLibOrm,
             wipeViews: isApplicationCore && spec.wipeViews,
             extensionLocation: isCoreExtension ? "/core-extensions" :
               isPublicExtension ? "/xtuple-extensions" :
-              isPrivateExtension ? "/private-extensions" : "not-applicable"
+              isPrivateExtension ? "/private-extensions" :
+              isNpmExtension ? "npm" : "not-applicable"
           };
 
-        buildDatabaseUtil.explodeManifest(path.join(dbSourceRoot, "manifest.js"),
-          manifestOptions, extensionCallback);
+        explodeManifest(manifestOptions, extensionCallback);
       };
 
       // We also need to get the sql that represents the queries to generate
@@ -211,17 +194,23 @@ var  async = require('async'),
         // on the case of error.
         allSql = "\\set ON_ERROR_STOP TRUE;\n" + allSql;
 
-        if (spec.wasInitialized && !_.isEqual(extensions, ["foundation-database"])) {
-          // give the admin user every extension by default
-          allSql = allSql + "insert into xt.usrext (usrext_usr_username, usrext_ext_id) " +
-            "select '" + creds.username +
-            "', ext_id from xt.ext where ext_location = '/core-extensions' and ext_name NOT LIKE 'oauth2';";
-        }
-
         winston.info("Applying build to database " + spec.database);
         credsClone.database = spec.database;
-        buildDatabaseUtil.sendToDatabase(allSql, credsClone, spec, function (err, res) {
-          databaseCallback(err, res);
+        sendToDatabase(allSql, credsClone, spec, function (err, res) {
+          if (spec.populateData && creds.encryptionKeyFile) {
+            var populateSql = "DO $$ XT.disableLocks = true; $$ language plv8;";
+            var encryptionKey = fs.readFileSync(path.resolve(__dirname, "../../node-datasource", creds.encryptionKeyFile), "utf8");
+            var patches = require(path.join(__dirname, "../../enyo-client/database/source/populate_data")).patches;
+            _.each(patches, function (patch) {
+              patch.encryptionKey = encryptionKey;
+              patch.username = creds.username;
+              populateSql += "select xt.patch(\'" + JSON.stringify(patch) + "\');";
+            });
+            populateSql += "DO $$ XT.disableLocks = undefined; $$ language plv8;";
+            dataSource.query(populateSql, credsClone, databaseCallback);
+          } else {
+            databaseCallback(err, res);
+          }
         });
       });
     };
diff --git a/scripts/lib/build_database_util.js b/scripts/lib/build_database_util.js
deleted file mode 100644 (file)
index 0cbb145..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
-regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global _:true */
-
-(function () {
-  "use strict";
-
-  var _ = require('underscore'),
-    async = require('async'),
-    exec = require('child_process').exec,
-    fs = require('fs'),
-    os = require('os'),
-    path = require('path'),
-    dataSource = require('../../node-datasource/lib/ext/datasource').dataSource,
-    winston = require('winston');
-
-
-
-
-  var convertFromMetasql = function (content, filename, defaultSchema) {
-    var lines = content.split("\n"),
-      schema = defaultSchema ? "'" + defaultSchema + "'" : "NULL",
-      group,
-      i = 2,
-      name,
-      notes = "",
-      grade = 0,
-      deleteSql,
-      insertSql;
-
-    if (lines[0].indexOf("-- Group: ") !== 0 ||
-        lines[1].indexOf("-- Name: ") !== 0 ||
-        lines[2].indexOf("-- Notes:") !== 0) {
-      throw new Error("Improperly formatted metasql: " + filename);
-    }
-    group = lines[0].substring("-- Group: ".length).trim();
-    name = lines[1].substring("-- Name: ".length).trim();
-    while (lines[i].indexOf("--") === 0) {
-      notes = notes + lines[i].substring(2) + "\n";
-      i++;
-    }
-    notes = notes.substring(" Notes:".length);
-    if (notes.indexOf("must be grade 10") >= 0) {
-      grade = 10;
-    }
-
-    insertSql = "select saveMetasql (" +
-      "'" + group + "'," +
-      "'" + name + "'," +
-      "$$" + notes + "$$," +
-      "$$" + content + "$$," +
-      "true, " + schema + ", " + grade + ");";
-
-    return insertSql;
-  };
-
-  var convertFromReport = function (content, filename, defaultSchema) {
-    var lines = content.split("\n"),
-      name,
-      grade = "0",
-      tableName = defaultSchema ? defaultSchema + ".pkgreport" : "report",
-      description,
-      disableSql,
-      deleteSql,
-      insertSql,
-      enableSql;
-
-    if (lines[3].indexOf(" <name>") !== 0 ||
-        lines[4].indexOf(" <description>") !== 0) {
-      throw new Error("Improperly formatted report");
-    }
-    name = lines[3].substring(" <name>".length).trim();
-    name = name.substring(0, name.indexOf("<"));
-    description = lines[4].substring(" <description>".length).trim();
-    description = description.substring(0, description.indexOf("<"));
-    if (lines[5].indexOf("grade") >= 0) {
-      grade = lines[5].substring(" <grade>".length).trim();
-      grade = grade.substring(0, grade.indexOf("<"));
-    }
-
-    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
-
-    deleteSql = "delete from " + tableName + " " +
-      "where report_name = '" + name +
-      "' and report_grade = " + grade + ";";
-
-    insertSql = "insert into " + tableName + " (report_name, report_descrip, " +
-      "report_source, report_loaddate, report_grade) VALUES (" +
-      "'" + name + "'," +
-      "$$" + description + "$$," +
-      "$$" + content + "$$," +
-      "now(), " + grade + ");";
-
-    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
-
-    return disableSql + deleteSql + insertSql + enableSql;
-  };
-
-  var convertFromScript = function (content, filename, defaultSchema) {
-    var name = path.basename(filename, '.js'),
-      tableName = defaultSchema ? defaultSchema + ".pkgscript" : "unknown",
-      notes = "", //"xtMfg package",
-      disableSql,
-      deleteSql,
-      insertSql,
-      enableSql;
-
-    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
-
-    deleteSql = "delete from " + tableName + " " +
-      "where script_name = '" + name +
-      "';";
-
-    insertSql = "insert into " + tableName + " (script_name, script_order, script_enabled, " +
-      "script_source, script_notes) VALUES (" +
-      "'" + name + "', 0, TRUE, " +
-      "$$" + content + "$$," +
-      "'" + notes + "');";
-
-    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
-
-    return disableSql + deleteSql + insertSql + enableSql;
-  };
-
-  var convertFromUiform = function (content, filename, defaultSchema) {
-    var name = path.basename(filename, '.ui'),
-      tableName = defaultSchema ? defaultSchema + ".pkguiform" : "unknown",
-      notes = "", //"xtMfg package",
-      disableSql,
-      deleteSql,
-      insertSql,
-      enableSql;
-
-    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
-
-    deleteSql = "delete from " + tableName + " " +
-      "where uiform_name = '" + name +
-      "';";
-
-    insertSql = "insert into " + tableName + " (uiform_name, uiform_order, uiform_enabled, " +
-      "uiform_source, uiform_notes) VALUES (" +
-      "'" + name + "', 0, TRUE, " +
-      "$$" + content + "$$," +
-      "'" + notes + "');";
-
-    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
-
-    return disableSql + deleteSql + insertSql + enableSql;
-  };
-
-  var conversionMap = {
-    mql: convertFromMetasql,
-    xml: convertFromReport,
-    js: convertFromScript,
-    ui: convertFromUiform,
-    sql: function (content) {
-      // no op
-      return content;
-    }
-  };
-
-  var explodeManifest = function (manifestFilename, options, manifestCallback) {
-    var dbSourceRoot = path.dirname(manifestFilename);
-    //
-    // Step 2:
-    // Read the manifest files.
-    //
-    if (!fs.existsSync(manifestFilename)) {
-      // error condition: no manifest file
-      manifestCallback("Cannot find manifest " + manifestFilename);
-      return;
-    }
-    fs.readFile(manifestFilename, "utf8", function (err, manifestString) {
-      var manifest,
-        databaseScripts,
-        extraManifestPath,
-        defaultSchema,
-        extraManifest,
-        extraManifestScripts,
-        alterPaths = dbSourceRoot.indexOf("foundation-database") < 0,
-        extensionName,
-        loadOrder,
-        extensionComment;
-
-      try {
-        manifest = JSON.parse(manifestString);
-        extensionName = manifest.name;
-        extensionComment = manifest.comment;
-        databaseScripts = manifest.databaseScripts;
-        defaultSchema = manifest.defaultSchema;
-        loadOrder = manifest.loadOrder || 999;
-
-      } catch (error) {
-        // error condition: manifest file is not properly formatted
-        manifestCallback("Manifest is not valid JSON" + manifestFilename);
-        return;
-      }
-
-      //
-      // Step 2b:
-      //
-
-      // supported use cases:
-
-      // 1. add mobilized inventory to quickbooks
-      // need the frozen_manifest, the foundation/manifest, and the mobile manifest
-      // -e ../private-extensions/source/inventory -f
-      // useFrozenScripts, useFoundationScripts
-
-      // 2. add mobilized inventory to masterref (foundation inventory is already there)
-      // need the the foundation/manifest and the mobile manifest
-      // -e ../private-extensions/source/inventory
-      // useFoundationScripts
-
-      // 3. add unmobilized inventory to quickbooks
-      // need the frozen_manifest and the foundation/manifest
-      // -e ../private-extensions/source/inventory/foundation-database -f
-      // useFrozenScripts (useFoundationScripts already taken care of by -e path)
-
-      // 4. upgrade unmobilized inventory
-      // not sure if this is necessary, but it would look like
-      // -e ../private-extensions/source/inventory/foundation-database
-
-      if (options.useFoundationScripts) {
-        extraManifest = JSON.parse(fs.readFileSync(path.join(dbSourceRoot, "../../foundation-database/manifest.js")));
-        defaultSchema = defaultSchema || extraManifest.defaultSchema;
-        extraManifestScripts = extraManifest.databaseScripts;
-        extraManifestScripts = _.map(extraManifestScripts, function (path) {
-          return "../../foundation-database/" + path;
-        });
-        databaseScripts.unshift(extraManifestScripts);
-        databaseScripts = _.flatten(databaseScripts);
-      }
-      if (options.useFrozenScripts) {
-        // Frozen files are not idempotent and should only be run upon first registration
-        extraManifestPath = alterPaths ?
-         path.join(dbSourceRoot, "../../foundation-database/frozen_manifest.js") :
-         path.join(dbSourceRoot, "frozen_manifest.js");
-
-        extraManifest = JSON.parse(fs.readFileSync(extraManifestPath));
-        defaultSchema = defaultSchema || extraManifest.defaultSchema;
-        extraManifestScripts = extraManifest.databaseScripts;
-        if (alterPaths) {
-          extraManifestScripts = _.map(extraManifestScripts, function (path) {
-            return "../../foundation-database/" + path;
-          });
-        }
-        databaseScripts.unshift(extraManifestScripts);
-        databaseScripts = _.flatten(databaseScripts);
-      }
-
-      //
-      // Step 3:
-      // Concatenate together all the files referenced in the manifest.
-      //
-      var getScriptSql = function (filename, scriptCallback) {
-        var fullFilename = path.join(dbSourceRoot, filename);
-        if (!fs.existsSync(fullFilename)) {
-          // error condition: script referenced in manifest.js isn't there
-          scriptCallback(path.join(dbSourceRoot, filename) + " does not exist");
-          return;
-        }
-        fs.readFile(fullFilename, "utf8", function (err, scriptContents) {
-          // error condition: can't read script
-          if (err) {
-            scriptCallback(err);
-            return;
-          }
-          var beforeNoticeSql = "do $$ BEGIN RAISE NOTICE 'Loading file " + path.basename(fullFilename) +
-              "'; END $$ language plpgsql;\n",
-            extname = path.extname(fullFilename).substring(1);
-
-          // convert special files: metasql, uiforms, reports, uijs
-          scriptContents = conversionMap[extname](scriptContents, fullFilename, defaultSchema);
-          //
-          // Allow inclusion of js files in manifest. If it is a js file,
-          // use plv8 to execute it.
-          //
-          //if (fullFilename.substring(fullFilename.length - 2) === 'js') {
-            // this isn't quite working yet
-            // http://adpgtech.blogspot.com/2013/03/loading-useful-modules-in-plv8.html
-            // put in lib/orm's manifest.js: "../../tools/lib/underscore/underscore-min.js",
-          //  scriptContents = "do $$ " + scriptContents + " $$ language plv8;";
-          //}
-
-          //
-          // Incorrectly-ended sql files (i.e. no semicolon) make for unhelpful error messages
-          // when we concatenate 100's of them together. Guard against these.
-          //
-          scriptContents = scriptContents.trim();
-          if (scriptContents.charAt(scriptContents.length - 1) !== ';') {
-            // error condition: script is improperly formatted
-            scriptCallback("Error: " + fullFilename + " contents do not end in a semicolon.");
-          }
-
-          scriptCallback(null, '\n' + scriptContents);
-        });
-      };
-      async.mapSeries(databaseScripts || [], getScriptSql, function (err, scriptSql) {
-        var registerSql,
-          dependencies;
-
-        if (err) {
-          manifestCallback(err);
-          return;
-        }
-        // each String of the scriptContents is the concatenated SQL for the script.
-        // join these all together into a single string for the whole extension.
-        var extensionSql = _.reduce(scriptSql, function (memo, script) {
-          return memo + script;
-        }, "");
-
-        if (options.registerExtension) {
-          // register extension and dependencies
-          extensionSql = 'do $$ plv8.elog(NOTICE, "About to register extension ' +
-            extensionName + '"); $$ language plv8;\n' + extensionSql;
-
-          registerSql = "select xt.register_extension('%@', '%@', '%@', '', %@);\n"
-            .f(extensionName, extensionComment, options.extensionLocation, loadOrder);
-
-          var grantExtToAdmin = "select xt.grant_role_ext('ADMIN', '%@');\n"
-            .f(extensionName);
-
-          extensionSql = grantExtToAdmin + extensionSql;
-
-          dependencies = manifest.dependencies || [];
-          _.each(dependencies, function (dependency) {
-            var dependencySql = "select xt.register_extension_dependency('%@', '%@');\n"
-                .f(extensionName, dependency),
-              grantDependToAdmin = "select xt.grant_role_ext('ADMIN', '%@');\n"
-                .f(dependency);
-
-            extensionSql = dependencySql + grantDependToAdmin + extensionSql;
-          });
-          extensionSql = registerSql + extensionSql;
-        }
-        if (options.runJsInit) {
-          // unless it it hasn't yet been defined (ie. lib/orm),
-          // running xt.js_init() is probably a good idea.
-          extensionSql = "select xt.js_init();" + extensionSql;
-        }
-
-        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/delete_system_orms.sql"),
-              function (err, wipeSql) {
-            if (err) {
-              manifestCallback(err);
-              return;
-            }
-            extensionSql = wipeSql + extensionSql;
-            manifestCallback(null, extensionSql);
-          });
-        } else {
-          manifestCallback(null, extensionSql);
-        }
-
-      });
-      //
-      // End script installation code
-      //
-    });
-  };
-
-  //
-  // Step 0 (optional, triggered by flags), wipe out the database
-  // and load it from scratch using pg_restore something.backup unless
-  // we're building from source.
-  //
-  var initDatabase = function (spec, creds, callback) {
-    var databaseName = spec.database,
-      credsClone = JSON.parse(JSON.stringify(creds)),
-      dropDatabase = function (done) {
-        winston.info("Dropping database " + databaseName);
-        // the calls to drop and create the database need to be run against the database "postgres"
-        credsClone.database = "postgres";
-        dataSource.query("drop database if exists " + databaseName + ";", credsClone, done);
-      },
-      createDatabase = function (done) {
-        winston.info("Creating database " + databaseName);
-        dataSource.query("create database " + databaseName + " template template1;", credsClone, done);
-      },
-      buildSchema = function (done) {
-        var schemaPath = path.join(path.dirname(spec.source), "440_schema.sql");
-        winston.info("Building schema for database " + databaseName);
-
-        exec("psql -U " + creds.username + " -h " + creds.hostname + " --single-transaction -p " +
-          creds.port + " -d " + databaseName + " -f " + schemaPath,
-          {maxBuffer: 40000 * 1024 /* 200x default */}, done);
-      },
-      populateData = function (done) {
-        winston.info("Populating data for database " + databaseName + " from " + spec.source);
-        exec("psql -U " + creds.username + " -h " + creds.hostname + " --single-transaction -p " +
-          creds.port + " -d " + databaseName + " -f " + spec.source,
-          {maxBuffer: 40000 * 1024 /* 200x default */}, done);
-      },
-      // use exec to restore the backup. The alternative, reading the backup file into a string to query
-      // doesn't work because the backup file is binary.
-      restoreBackup = function (done) {
-        exec("pg_restore -U " + creds.username + " -h " + creds.hostname + " -p " +
-          creds.port + " -d " + databaseName + " -j " + os.cpus().length + " " + spec.backup, function (err, res) {
-          if (err) {
-            console.log("ignoring restore db error", err);
-          }
-          callback(null, res);
-        });
-      },
-      finish = function (err, results) {
-        if (err) {
-          winston.error("init database error", err.message, err.stack, err);
-        }
-        callback(err, results);
-      };
-
-    if (spec.source) {
-      async.series([
-        dropDatabase,
-        createDatabase,
-        buildSchema,
-        populateData
-      ], finish);
-    } else {
-      async.series([
-        dropDatabase,
-        createDatabase,
-        restoreBackup
-      ], finish);
-    }
-  };
-
-
-  var sendToDatabase = function (query, credsClone, options, callback) {
-    var filename = path.join(__dirname, "temp_query_" + credsClone.database + ".sql");
-    fs.writeFile(filename, query, function (err) {
-      if (err) {
-        winston.error("Cannot write query to file");
-        callback(err);
-        return;
-      }
-      var psqlCommand = 'psql -d ' + credsClone.database +
-        ' -U ' + credsClone.username +
-        ' -h ' + credsClone.hostname +
-        ' -p ' + credsClone.port +
-        ' -f ' + filename +
-        ' --single-transaction';
-
-
-      /**
-       * http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
-       * "maxBuffer specifies the largest amount of data allowed on stdout or
-       * stderr - if this value is exceeded then the child process is killed."
-       */
-      exec(psqlCommand, {maxBuffer: 40000 * 1024 /* 200x default */}, function (err, stdout, stderr) {
-        if (err) {
-          winston.error("Cannot install file ", filename);
-          callback(err);
-          return;
-        }
-        if (options.keepSql) {
-          // do not delete the temp query file
-          winston.info("SQL file kept as ", filename);
-          callback();
-        } else {
-          fs.unlink(filename, function (err) {
-            if (err) {
-              winston.error("Cannot delete written query file");
-              callback(err);
-            }
-            callback();
-          });
-        }
-      });
-    });
-  };
-
-  //
-  // Another option: unregister the extension
-  //
-  var unregister = function (specs, creds, masterCallback) {
-    var extension = path.basename(specs[0].extensions[0]),
-      unregisterSql = ["delete from xt.usrext where usrext_id in " +
-        "(select usrext_id from xt.usrext inner join xt.ext on usrext_ext_id = ext_id where ext_name = $1);",
-
-        "delete from xt.clientcode where clientcode_id in " +
-        "(select clientcode_id from xt.clientcode inner join xt.ext on clientcode_ext_id = ext_id where ext_name = $1);",
-
-        "delete from xt.dict where dict_id in " +
-        "(select dict_id from xt.dict inner join xt.ext on dict_ext_id = ext_id where ext_name = $1);",
-
-        "delete from xt.extdep where extdep_id in " +
-        "(select extdep_id from xt.extdep inner join xt.ext " +
-        "on extdep_from_ext_id = ext_id or extdep_to_ext_id = ext_id where ext_name = $1);",
-
-        "delete from xt.ext where ext_name = $1;"];
-
-    if (extension.charAt(extension.length - 1) === "/") {
-      // remove trailing slash if present
-      extension = extension.substring(0, extension.length - 1);
-    }
-    winston.info("Unregistering extension:", extension);
-    var unregisterEach = function (spec, callback) {
-      var options = JSON.parse(JSON.stringify(creds));
-      options.database = spec.database;
-      options.parameters = [extension];
-      var queryEach = function (sql, sqlCallback) {
-        dataSource.query(sql, options, sqlCallback);
-      };
-      async.eachSeries(unregisterSql, queryEach, callback);
-    };
-    async.each(specs, unregisterEach, masterCallback);
-  };
-
-  exports.explodeManifest = explodeManifest;
-  exports.initDatabase = initDatabase;
-  exports.sendToDatabase = sendToDatabase;
-  exports.unregister = unregister;
-}());
index cb86ad4..77ffc44 100644 (file)
@@ -201,6 +201,13 @@ if (typeof XT === 'undefined') {
               source: stringObj.value,
               target: preExistingTranslation
             });
+          } else if ( destinationLang.indexOf('en') === 0 ) {
+             // if locale is en_AU en_GB copy the en_US source: strings to target:
+             stringCallback(null, {
+               key: stringObj.key,
+               source: stringObj.value,
+               target: stringObj.value
+             });
           } else {
             // ask google (or not)
             autoTranslate(stringObj.value, apiKey, destinationLang, function (err, target) {
@@ -210,7 +217,7 @@ if (typeof XT === 'undefined') {
                 target: target
               });
             });
-          }
+         }
         };
         async.map(stringsArray, processString, function (err, strings) {
           extensionCallback(null, {
@@ -255,14 +262,11 @@ if (typeof XT === 'undefined') {
   /**
     Takes a dictionary definition file and inserts the data into the database
    */
-  exports.importDictionary = function (database, filename, masterCallback) {
+  var importDictionary = exports.importDictionary = function (database, filename, masterCallback) {
     var creds = require("../../node-datasource/config").databaseServer;
     creds.database = database;
 
-    // the filename relative unless it starts with a slash
-    if (filename.substring(0, 1) !== '/') {
-      filename = path.join(process.cwd(), filename);
-    }
+    filename = path.resolve(process.cwd(), filename);
     if (path.extname(filename) !== '.js') {
       console.log("Skipping non-dictionary file", filename);
       masterCallback();
@@ -292,4 +296,20 @@ if (typeof XT === 'undefined') {
     });
   };
 
+  exports.importAllDictionaries = function (database, callback) {
+    var translationsDir = path.join(__dirname, "../../node_modules/xtuple-linguist/translations");
+    if (!fs.existsSync(translationsDir)) {
+      console.log("No translations directory found. Ignoring linguist.");
+      return callback();
+    }
+    var importOne = function (dictionary, next) {
+      importDictionary(database, dictionary, next);
+    };
+    var allDictionaries = _.map(fs.readdirSync(translationsDir), function (filename) {
+      return path.join(translationsDir, filename);
+    });
+    async.map(allDictionaries, importOne, callback);
+  };
+
+
 }());
diff --git a/scripts/lib/util/convert_specialized.js b/scripts/lib/util/convert_specialized.js
new file mode 100644 (file)
index 0000000..95b8d52
--- /dev/null
@@ -0,0 +1,164 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var path = require('path');
+
+  var convertFromMetasql = function (content, filename, defaultSchema) {
+    var lines = content.split("\n"),
+      schema = defaultSchema ? "'" + defaultSchema + "'" : "NULL",
+      group,
+      i = 2,
+      name,
+      notes = "",
+      grade = 0,
+      deleteSql,
+      insertSql;
+
+    if (lines[0].indexOf("-- Group: ") !== 0 ||
+        lines[1].indexOf("-- Name: ") !== 0 ||
+        lines[2].indexOf("-- Notes:") !== 0) {
+      throw new Error("Improperly formatted metasql: " + filename);
+    }
+    group = lines[0].substring("-- Group: ".length).trim();
+    name = lines[1].substring("-- Name: ".length).trim();
+    while (lines[i].indexOf("--") === 0) {
+      notes = notes + lines[i].substring(2) + "\n";
+      i++;
+    }
+    notes = notes.substring(" Notes:".length);
+    if (notes.indexOf("must be grade 10") >= 0) {
+      grade = 10;
+    }
+
+    insertSql = "select saveMetasql (" +
+      "'" + group + "'," +
+      "'" + name + "'," +
+      "$$" + notes + "$$," +
+      "$$" + content + "$$," +
+      "true, " + schema + ", " + grade + ");";
+
+    return insertSql;
+  };
+
+  var convertFromReport = function (content, filename, defaultSchema) {
+    var lines = content.split("\n"),
+      name,
+      grade = "0",
+      tableName = defaultSchema ? defaultSchema + ".pkgreport" : "report",
+      description,
+      disableSql,
+      updateSql,
+      insertSql,
+      enableSql;
+
+    if (lines[3].indexOf(" <name>") !== 0 ||
+        lines[4].indexOf(" <description>") !== 0) {
+      throw new Error("Improperly formatted report");
+    }
+    name = lines[3].substring(" <name>".length).trim();
+    name = name.substring(0, name.indexOf("<"));
+    description = lines[4].substring(" <description>".length).trim();
+    description = description.substring(0, description.indexOf("<"));
+    if (lines[5].indexOf("grade") >= 0) {
+      grade = lines[5].substring(" <grade>".length).trim();
+      grade = grade.substring(0, grade.indexOf("<"));
+    }
+
+    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
+
+    insertSql = "insert into " + tableName + " (report_name, report_descrip, " +
+      "report_source, report_loaddate, report_grade) select " +
+      "'" + name + "'," +
+      "$$" + description + "$$," +
+      "$$" + content + "$$," +
+      "now(), " + grade +
+      " where not exists (select c.report_id from " + tableName + " c " +
+      "where report_name = '" + name +
+      "' and report_grade = " + grade + ");";
+
+    updateSql = "update " + tableName + " set " +
+      " report_descrip = $$" + description +
+      "$$, report_source = $$" + content +
+      "$$, report_loaddate = now() " +
+      "where report_name = '" + name +
+      "' and report_grade = " + grade + ";";
+
+    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
+
+    return disableSql + insertSql + updateSql + enableSql;
+  };
+
+  var convertFromScript = function (content, filename, defaultSchema) {
+    var name = path.basename(filename, '.js'),
+      tableName = defaultSchema ? defaultSchema + ".pkgscript" : "unknown",
+      notes = "", //"xtMfg package",
+      disableSql,
+      insertSql,
+      updateSql,
+      enableSql;
+
+    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
+
+    insertSql = "insert into " + tableName + " (script_name, script_order, script_enabled, " +
+      "script_source, script_notes) select " +
+      "'" + name + "', 0, TRUE, " +
+      "$$" + content + "$$," +
+      "'" + notes + "'" +
+      " where not exists (select c.script_id from " + tableName + " c " +
+      "where script_name = '" + name + "');";
+
+    updateSql = "update " + tableName + " set " +
+      "script_name = '" + name + "', script_order = 0, script_enabled = TRUE, " +
+      "script_source = $$" + content +
+      "$$, script_notes = '" + notes + "' " +
+      "where script_name = '" + name + "';";
+
+    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
+
+    return disableSql + insertSql + updateSql + enableSql;
+  };
+
+  var convertFromUiform = function (content, filename, defaultSchema) {
+    var name = path.basename(filename, '.ui'),
+      tableName = defaultSchema ? defaultSchema + ".pkguiform" : "unknown",
+      notes = "", //"xtMfg package",
+      disableSql,
+      insertSql,
+      updateSql,
+      enableSql;
+
+    disableSql = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL;";
+
+    insertSql = "insert into " + tableName + " (uiform_name, uiform_order, uiform_enabled, " +
+      "uiform_source, uiform_notes) select " +
+      "'" + name + "', 0, TRUE, " +
+      "$$" + content + "$$," +
+      "'" + notes + "' " +
+      " where not exists (select c.uiform_id from " + tableName + " c " +
+      "where uiform_name = '" + name + "');";
+
+    updateSql = "update " + tableName + " set uiform_name = '" +
+      name + "', uiform_order = 0, uiform_enabled = TRUE, " +
+      "uiform_source = $$" + content + "$$, uiform_notes = '" + notes + "' " +
+      "where uiform_name = '" + name + "';";
+
+    enableSql = "ALTER TABLE " + tableName + " ENABLE TRIGGER ALL;";
+
+    return disableSql + insertSql + updateSql + enableSql;
+  };
+
+  exports.conversionMap = {
+    mql: convertFromMetasql,
+    xml: convertFromReport,
+    js: convertFromScript,
+    ui: convertFromUiform,
+    sql: function (content) {
+      // no op
+      return content;
+    }
+  };
+}());
diff --git a/scripts/lib/util/default_extensions.js b/scripts/lib/util/default_extensions.js
new file mode 100644 (file)
index 0000000..ffaf37c
--- /dev/null
@@ -0,0 +1,21 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var path = require('path');
+
+  exports.extensions = [
+    path.join(__dirname, '../../../foundation-database'),
+    path.join(__dirname, '../../../lib/orm'),
+    path.join(__dirname, '../../../enyo-client'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/crm'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/project'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/sales'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/billing'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/purchasing'),
+    path.join(__dirname, '../../../enyo-client/extensions/source/oauth2')
+  ];
+}());
diff --git a/scripts/lib/util/init_database.js b/scripts/lib/util/init_database.js
new file mode 100644 (file)
index 0000000..3794cfb
--- /dev/null
@@ -0,0 +1,99 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var async = require("async"),
+    proc = require('child_process'),
+    path = require('path'),
+    os = require('os'),
+    winston = require('winston'),
+    dataSource = require('../../../node-datasource/lib/ext/datasource').dataSource,
+    inspectDatabaseExtensions = require("./inspect_database").inspectDatabaseExtensions;
+
+  //
+  // Wipe out the database
+  // and load it from scratch using pg_restore something.backup unless
+  // we're building from source.
+  //
+  var initDatabase = function (spec, creds, callback) {
+    var databaseName = spec.database,
+      credsClone = JSON.parse(JSON.stringify(creds)),
+      dropDatabase = function (done) {
+        winston.info("Dropping database " + databaseName);
+        // the calls to drop and create the database need to be run against the database "postgres"
+        credsClone.database = "postgres";
+        dataSource.query("drop database if exists " + databaseName + ";", credsClone, done);
+      },
+      createDatabase = function (done) {
+        winston.info("Creating database " + databaseName);
+        dataSource.query("create database " + databaseName + " template template1;", credsClone, done);
+      },
+      buildSchema = function (done) {
+        var schemaPath = path.join(path.dirname(spec.source), "440_schema.sql");
+        winston.info("Building schema for database " + databaseName);
+
+        var process = proc.spawn('psql', [
+          '-q', '-U', creds.username, '-h', creds.hostname, '--single-transaction', '-p',
+          creds.port, '-d', databaseName, '-f', schemaPath
+        ], { stdio: 'inherit' });
+        process.on('exit', done);
+        
+      },
+      populateData = function (done) {
+        winston.info("Populating data for database " + databaseName + " from " + spec.source);
+        var process = proc.spawn('psql', [
+          '-q', '-U', creds.username, '-h', creds.hostname, '--single-transaction', '-p',
+          creds.port, '-d', databaseName, '-f', spec.source
+        ], { stdio: 'inherit'});
+        process.on('exit', done);
+      },
+      // use exec to restore the backup. The alternative, reading the backup file into a string to query
+      // doesn't work because the backup file is binary.
+      restoreBackup = function (done) {
+        var process = proc.spawn('pg_restore', [
+          '-U', creds.username, '-h', creds.hostname, '-p', creds.port, '-d', databaseName,
+          '-j', os.cpus().length, spec.backup
+        ], { stdio: 'inherit' });
+        process.on('exit', function (err, res) {
+          if (err) {
+            console.log("ignoring restore db error", err);
+          }
+          done(null, res);
+        });
+      },
+      finish = function (err, results) {
+        if (err) {
+          winston.error("init database error", err.message, err.stack, err);
+        }
+        callback(err, results);
+      };
+
+    if (spec.source) {
+      async.series([
+        dropDatabase,
+        createDatabase,
+        buildSchema,
+        populateData
+      ], finish);
+    } else {
+      async.series([
+        dropDatabase,
+        createDatabase,
+        restoreBackup,
+        function (done) {
+          credsClone.database = databaseName;
+          inspectDatabaseExtensions(credsClone, function (err, paths) {
+            // in the case of a build-from-backup, we ignore any user desires and dictate the extensions
+            spec.extensions = paths;
+            done();
+          });
+        }
+      ], finish);
+    }
+  };
+
+  exports.initDatabase = initDatabase;
+}());
diff --git a/scripts/lib/util/inspect_database.js b/scripts/lib/util/inspect_database.js
new file mode 100644 (file)
index 0000000..2f1e849
--- /dev/null
@@ -0,0 +1,79 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var path = require('path'),
+    dataSource = require('../../../node-datasource/lib/ext/datasource').dataSource,
+    defaultExtensions = require("./default_extensions").extensions;
+
+  var pathFromExtension = function (name, location) {
+    if (location === '/core-extensions') {
+      return path.join(__dirname, "../../../enyo-client/extensions/source/", name);
+    } else if (location === '/xtuple-extensions') {
+      return path.join(__dirname, "../../../../xtuple-extensions/source", name);
+    } else if (location === '/private-extensions') {
+      return path.join(__dirname, "../../../../private-extensions/source", name);
+    } else if (location === 'npm') {
+      return path.join(__dirname, "../../../node_modules", name);
+    }
+  };
+
+  //
+  // Looks in a database to see which extensions are registered, and
+  // tacks onto that list the core directories.
+  //
+  var inspectMobilizedDatabase = function (creds, done) {
+    var extSql = "SELECT * FROM xt.ext ORDER BY ext_load_order";
+    dataSource.query(extSql, creds, function (err, res) {
+      if (err) {
+        return done(err);
+      }
+
+      var paths = _.map(_.compact(res.rows), function (row) {
+        return pathFromExtension(row.ext_name, row.ext_location);
+      });
+
+      paths.unshift(path.join(__dirname, "../../../enyo-client")); // core path
+      paths.unshift(path.join(__dirname, "../../../lib/orm")); // lib path
+      paths.unshift(path.join(__dirname, "../../../foundation-database")); // foundation path
+      done(null, _.compact(paths));
+    });
+  };
+
+  var inspectUnmobilizedDatabase = function (creds, done) {
+    var extSql = "select * from public.pkghead where pkghead_name in ('xtmfg', 'xwd');",
+      editionMap = {
+        xtmfg: ["inventory", "manufacturing"],
+        xwd: ["inventory", "distribution"]
+      };
+    dataSource.query(extSql, creds, function (err, res) {
+      if (err) {
+        return done(err);
+      }
+      var extensions = _.unique(_.flatten(_.map(res.rows, function (row) {
+        return _.map(editionMap[row.pkghead_name], function (ext) {
+          return path.join(__dirname, "../../../../private-extensions/source", ext);
+        });
+      })));
+      done(err, defaultExtensions.concat(extensions));
+    });
+  };
+
+  var inspectDatabaseExtensions = function (creds, done) {
+    var isMobilizedSql = "select * from information_schema.tables where table_schema = 'xt' and table_name = 'ext';";
+
+    dataSource.query(isMobilizedSql, creds, function (err, res) {
+      if (res.rowCount === 0) {
+        inspectUnmobilizedDatabase(creds, done);
+      } else {
+        inspectMobilizedDatabase(creds, done);
+      }
+    });
+  };
+
+  exports.inspectDatabaseExtensions = inspectDatabaseExtensions;
+
+}());
diff --git a/scripts/lib/util/process_manifest.js b/scripts/lib/util/process_manifest.js
new file mode 100644 (file)
index 0000000..90f6030
--- /dev/null
@@ -0,0 +1,227 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var _ = require('underscore'),
+    async = require('async'),
+    exec = require('child_process').exec,
+    fs = require('fs'),
+    path = require('path'),
+    conversionMap = require("./convert_specialized").conversionMap,
+    dataSource = require('../../../node-datasource/lib/ext/datasource').dataSource,
+    inspectDatabaseExtensions = require("./inspect_database").inspectDatabaseExtensions;
+
+  // register extension and dependencies
+  var getRegistrationSql = function (options, extensionLocation) {
+    var registerSql = 'do $$ plv8.elog(NOTICE, "About to register extension ' +
+      options.name + '"); $$ language plv8;\n';
+
+    registerSql = registerSql + "select xt.register_extension('%@', '%@', '%@', '', %@);\n"
+      .f(options.name, options.description || options.comment, extensionLocation, options.loadOrder || 9999);
+
+    registerSql = registerSql + "select xt.grant_role_ext('ADMIN', '%@');\n"
+      .f(options.name);
+
+    // TODO: infer dependencies from package.json using peerDependencies
+    var dependencies = options.dependencies || [];
+    _.each(dependencies, function (dependency) {
+      var dependencySql = "select xt.register_extension_dependency('%@', '%@');\n"
+          .f(options.name, dependency),
+        grantDependToAdmin = "select xt.grant_role_ext('ADMIN', '%@');\n"
+          .f(dependency);
+
+      registerSql = registerSql + dependencySql + grantDependToAdmin;
+    });
+    return registerSql;
+  };
+
+  var composeExtensionSql = function (scriptSql, packageFile, options, callback) {
+    // each String of the scriptContents is the concatenated SQL for the script.
+    // join these all together into a single string for the whole extension.
+    var extensionSql = _.reduce(scriptSql, function (memo, script) {
+      return memo + script;
+    }, "");
+
+    if (options.registerExtension) {
+      extensionSql = getRegistrationSql(packageFile, options.extensionLocation) +
+        extensionSql;
+    }
+    if (options.runJsInit) {
+      // unless it it hasn't yet been defined (ie. lib/orm),
+      // running xt.js_init() is probably a good idea.
+      extensionSql = "select xt.js_init();" + extensionSql;
+    }
+
+    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/delete_system_orms.sql"),
+          function (err, wipeSql) {
+        if (err) {
+          callback(err);
+          return;
+        }
+        extensionSql = wipeSql + extensionSql;
+        callback(null, extensionSql);
+      });
+    } else {
+      callback(null, extensionSql);
+    }
+  };
+
+  var explodeManifest = function (options, manifestCallback) {
+    var manifestFilename = options.manifestFilename;
+    var packageJson;
+    var dbSourceRoot = path.dirname(manifestFilename);
+
+    if (options.extensionPath && fs.existsSync(path.resolve(options.extensionPath, "package.json"))) {
+      packageJson = require(path.resolve(options.extensionPath, "package.json"));
+    }
+    //
+    // Step 2:
+    // Read the manifest files.
+    //
+
+    if (!fs.existsSync(manifestFilename) && packageJson) {
+      console.log("No manifest file " + manifestFilename + ". There is probably no db-side code in the extension.");
+      composeExtensionSql([], packageJson, options, manifestCallback);
+      return;
+
+    } else if (!fs.existsSync(manifestFilename)) {
+      // error condition: no manifest file
+      manifestCallback("Cannot find manifest " + manifestFilename);
+      return;
+    }
+    fs.readFile(manifestFilename, "utf8", function (err, manifestString) {
+      var manifest,
+        databaseScripts,
+        extraManifestPath,
+        defaultSchema,
+        extraManifest,
+        extraManifestScripts,
+        alterPaths = dbSourceRoot.indexOf("foundation-database") < 0;
+
+      try {
+        manifest = JSON.parse(manifestString);
+        databaseScripts = manifest.databaseScripts;
+        defaultSchema = manifest.defaultSchema;
+
+      } catch (error) {
+        // error condition: manifest file is not properly formatted
+        manifestCallback("Manifest is not valid JSON" + manifestFilename);
+        return;
+      }
+
+      //
+      // Step 2b:
+      //
+
+      // supported use cases:
+
+      // 1. add mobilized inventory to quickbooks
+      // need the frozen_manifest, the foundation/manifest, and the mobile manifest
+      // -e ../private-extensions/source/inventory -f
+      // useFrozenScripts, useFoundationScripts
+
+      // 2. add mobilized inventory to masterref (foundation inventory is already there)
+      // need the the foundation/manifest and the mobile manifest
+      // -e ../private-extensions/source/inventory
+      // useFoundationScripts
+
+      // 3. add unmobilized inventory to quickbooks
+      // need the frozen_manifest and the foundation/manifest
+      // -e ../private-extensions/source/inventory/foundation-database -f
+      // useFrozenScripts (useFoundationScripts already taken care of by -e path)
+
+      // 4. upgrade unmobilized inventory
+      // not sure if this is necessary, but it would look like
+      // -e ../private-extensions/source/inventory/foundation-database
+
+      if (options.useFoundationScripts) {
+        extraManifest = JSON.parse(fs.readFileSync(path.join(dbSourceRoot, "../../foundation-database/manifest.js")));
+        defaultSchema = defaultSchema || extraManifest.defaultSchema;
+        extraManifestScripts = extraManifest.databaseScripts;
+        extraManifestScripts = _.map(extraManifestScripts, function (path) {
+          return "../../foundation-database/" + path;
+        });
+        databaseScripts.unshift(extraManifestScripts);
+        databaseScripts = _.flatten(databaseScripts);
+      }
+      if (options.useFrozenScripts) {
+        // Frozen files are not idempotent and should only be run upon first registration
+        extraManifestPath = alterPaths ?
+         path.join(dbSourceRoot, "../../foundation-database/frozen_manifest.js") :
+         path.join(dbSourceRoot, "frozen_manifest.js");
+
+        extraManifest = JSON.parse(fs.readFileSync(extraManifestPath));
+        defaultSchema = defaultSchema || extraManifest.defaultSchema;
+        extraManifestScripts = extraManifest.databaseScripts;
+        if (alterPaths) {
+          extraManifestScripts = _.map(extraManifestScripts, function (path) {
+            return "../../foundation-database/" + path;
+          });
+        }
+        databaseScripts.unshift(extraManifestScripts);
+        databaseScripts = _.flatten(databaseScripts);
+      }
+
+      //
+      // Step 3:
+      // Concatenate together all the files referenced in the manifest.
+      //
+      var getScriptSql = function (filename, scriptCallback) {
+        var fullFilename = path.join(dbSourceRoot, filename);
+        if (!fs.existsSync(fullFilename)) {
+          // error condition: script referenced in manifest.js isn't there
+          scriptCallback(path.join(dbSourceRoot, filename) + " does not exist");
+          return;
+        }
+        fs.readFile(fullFilename, "utf8", function (err, scriptContents) {
+          // error condition: can't read script
+          if (err) {
+            scriptCallback(err);
+            return;
+          }
+          var beforeNoticeSql = "do $$ BEGIN RAISE NOTICE 'Loading file " + path.basename(fullFilename) +
+              "'; END $$ language plpgsql;\n",
+            extname = path.extname(fullFilename).substring(1);
+
+          // convert special files: metasql, uiforms, reports, uijs
+          scriptContents = conversionMap[extname](scriptContents, fullFilename, defaultSchema);
+
+          //
+          // Incorrectly-ended sql files (i.e. no semicolon) make for unhelpful error messages
+          // when we concatenate 100's of them together. Guard against these.
+          //
+          scriptContents = scriptContents.trim();
+          if (scriptContents.charAt(scriptContents.length - 1) !== ';') {
+            // error condition: script is improperly formatted
+            scriptCallback("Error: " + fullFilename + " contents do not end in a semicolon.");
+          }
+
+          scriptCallback(null, '\n' + scriptContents);
+        });
+      };
+      async.mapSeries(databaseScripts || [], getScriptSql, function (err, scriptSql) {
+        var registerSql,
+          dependencies;
+
+        if (err) {
+          manifestCallback(err);
+          return;
+        }
+
+        composeExtensionSql(scriptSql, packageJson || manifest, options, manifestCallback);
+
+      });
+      //
+      // End script installation code
+      //
+    });
+  };
+
+  exports.explodeManifest = explodeManifest;
+}());
diff --git a/scripts/lib/util/send_to_database.js b/scripts/lib/util/send_to_database.js
new file mode 100644 (file)
index 0000000..939f280
--- /dev/null
@@ -0,0 +1,59 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var exec = require('child_process').exec,
+    fs = require('fs'),
+    path = require('path'),
+    winston = require('winston');
+
+  var sendToDatabase = function (query, credsClone, options, callback) {
+    var filename = path.join(__dirname, "../../output/build_" + credsClone.database + ".sql");
+    if (!fs.existsSync(path.join(__dirname, "../../output"))) {
+      fs.mkdirSync(path.join(__dirname, "../../output"));
+    }
+    fs.writeFile(filename, query, function (err) {
+      if (err) {
+        winston.error("Cannot write query to file");
+        callback(err);
+        return;
+      }
+      var psqlCommand = 'psql -d ' + credsClone.database +
+        ' -U ' + credsClone.username +
+        ' -h ' + credsClone.hostname +
+        ' -p ' + credsClone.port +
+        ' -f ' + filename +
+        ' --single-transaction';
+
+      /**
+       * http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
+       * "maxBuffer specifies the largest amount of data allowed on stdout or
+       * stderr - if this value is exceeded then the child process is killed."
+       */
+      exec(psqlCommand, {maxBuffer: 40000 * 1024 /* 200x default */}, function (err, stdout, stderr) {
+        if (err) {
+          winston.error("Cannot install file ", filename);
+          callback(err);
+          return;
+        }
+        if (options.keepSql) {
+          // do not delete the temp query file
+          winston.info("SQL file kept as ", filename);
+          callback();
+        } else {
+          fs.unlink(filename, function (err) {
+            if (err) {
+              winston.error("Cannot delete written query file");
+              callback(err);
+            }
+            callback();
+          });
+        }
+      });
+    });
+  };
+  exports.sendToDatabase = sendToDatabase;
+}());
diff --git a/scripts/lib/util/unregister.js b/scripts/lib/util/unregister.js
new file mode 100644 (file)
index 0000000..d727a5a
--- /dev/null
@@ -0,0 +1,55 @@
+/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global _:true */
+
+(function () {
+  "use strict";
+
+  var async = require("async"),
+    path = require('path'),
+    winston = require('winston'),
+    dataSource = require('../../../node-datasource/lib/ext/datasource').dataSource;
+
+  //
+  // Unregister the extension
+  //
+  var unregister = function (specs, creds, masterCallback) {
+    var extension = path.basename(specs[0].extensions[0]),
+      unregisterSql = ["delete from xt.usrext where usrext_id in " +
+        "(select usrext_id from xt.usrext inner join xt.ext on usrext_ext_id = ext_id where ext_name = $1);",
+
+        "delete from xt.grpext where grpext_id in " +
+        "(select grpext_id from xt.grpext inner join xt.ext on grpext_ext_id = ext_id where ext_name = $1);",
+
+        "delete from xt.clientcode where clientcode_id in " +
+        "(select clientcode_id from xt.clientcode inner join xt.ext on clientcode_ext_id = ext_id where ext_name = $1);",
+
+        "delete from xt.dict where dict_id in " +
+        "(select dict_id from xt.dict inner join xt.ext on dict_ext_id = ext_id where ext_name = $1);",
+
+        "delete from xt.extdep where extdep_id in " +
+        "(select extdep_id from xt.extdep inner join xt.ext " +
+        "on extdep_from_ext_id = ext_id or extdep_to_ext_id = ext_id where ext_name = $1);",
+
+        "delete from xt.ext where ext_name = $1;"];
+
+    if (extension.charAt(extension.length - 1) === "/") {
+      // remove trailing slash if present
+      extension = extension.substring(0, extension.length - 1);
+    }
+    winston.info("Unregistering extension:", extension);
+    var unregisterEach = function (spec, callback) {
+      var options = JSON.parse(JSON.stringify(creds));
+      options.database = spec.database;
+      options.parameters = [extension];
+      var queryEach = function (sql, sqlCallback) {
+        dataSource.query(sql, options, sqlCallback);
+      };
+      async.eachSeries(unregisterSql, queryEach, callback);
+    };
+    async.each(specs, unregisterEach, masterCallback);
+  };
+
+  exports.unregister = unregister;
+}());
+
index 7594812..133bf95 100755 (executable)
@@ -70,7 +70,7 @@ tar -zcvf manufacturing-upgrade-$MAJ$MIN$PAT.gz manufacturing-upgrade-$MAJ$MIN$P
 #manufacturing install
 cd ../../
 mkdir scripts/output/manufacturing-install-$MAJ$MIN$PAT
-cp scripts/xml/xtmfg_package.xml scripts/output/manufacturing-install-$MAJ$MIN$PAT/package.xml
+cp scripts/xml/xtmfg_install.xml scripts/output/manufacturing-install-$MAJ$MIN$PAT/package.xml
 cp scripts/output/postbooks_upgrade.sql scripts/output/manufacturing-install-$MAJ$MIN$PAT
 cp scripts/output/inventory_basic_install.sql scripts/output/manufacturing-install-$MAJ$MIN$PAT
 cp scripts/output/inventory_upgrade.sql scripts/output/manufacturing-install-$MAJ$MIN$PAT
diff --git a/scripts/start_bi.sh b/scripts/start_bi.sh
deleted file mode 100755 (executable)
index 491a3f4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-LOG_FILE='start_bi.log'
-log() {
-       echo $@
-       echo $@ >> $LOG_FILE
-}
-cdir() {
-       cd $1
-       log "Changing directory to $1"
-}
-log ""
-log "######################################################"
-log "######################################################"
-log "Start BI server listening on port 8843                "
-log "######################################################"
-log "######################################################"
-log ""
-cdir ../../ErpBI/biserver-ce/
-./start-pentaho.sh
-
-log ""
-log "######################################################"
-log "######################################################"
-log "Refresh repository and clear OLAP Cache.             "
-log "######################################################"
-log "######################################################"
-log ""
-
-sleep 10
-
-wget -O tempresponse.txt "http://localhost:8080/pentaho/Publish?publish=now&class=org.pentaho.platform.engine.services.solution.SolutionPublisher&userid=admin&password=Car54WhereRU"
-rm tempresponse.txt
-wget -O tempresponse.txt "http://localhost:8080/pentaho/ViewAction?solution=admin&path=&action=clear_mondrian_schema_cache.xaction&userid=admin&password=Car54WhereRU"
-rm tempresponse.txt
\ No newline at end of file
diff --git a/scripts/stop_bi.sh b/scripts/stop_bi.sh
deleted file mode 100755 (executable)
index 857603b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-LOG_FILE='stop_bi.log'
-log() {
-       echo $@
-       echo $@ >> $LOG_FILE
-}
-cdir() {
-       cd $1
-       log "Changing directory to $1"
-}
-log ""
-log "######################################################"
-log "######################################################"
-log "Stop BI server listening on port 8843                "
-log "######################################################"
-log "######################################################"
-log ""
-cdir ../../ErpBI/biserver-ce/
-./stop-pentaho.sh
-
diff --git a/scripts/templates/README.md b/scripts/templates/README.md
deleted file mode 100755 (executable)
index fbdd7db..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-To create or use your own template, create a folder, and give it the name of your template, for example "mycooltemplate". Within this folder create a file named "publish.js". That file must define a global method named "publish". For example:
-
-````javascript
-/**
- * Turn the data about your docs into file output.
- * @global
- * @param {TAFFY} data - A TaffyDB collection representing
- *                       all the symbols documented in your code.
- * @param {object} opts - An object with options information.
- */
-function publish(data, opts) {
-    // do stuff here to generate your output files
-}
-````
-
-To invoke JSDoc 3 with your own template, use the `-t` command line option, giving it the path to your template folder.
-
-````
-./jsdoc mycode.js -t /path/to/mycooltemplate
-````
\ No newline at end of file
diff --git a/scripts/templates/xtuple/README.md b/scripts/templates/xtuple/README.md
deleted file mode 100644 (file)
index a7bd96b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-The default template for JSDoc 3 uses: [the Taffy Database library](http://taffydb.com/) and the [Underscore Template library](http://documentcloud.github.com/underscore/#template).
diff --git a/scripts/templates/xtuple/publish.js b/scripts/templates/xtuple/publish.js
deleted file mode 100644 (file)
index b79200a..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*global env: true */
-var template = require('jsdoc/template'),
-    fs = require('jsdoc/fs'),
-    path = require('jsdoc/path'),
-    taffy = require('taffydb').taffy,
-    handle = require('jsdoc/util/error').handle,
-    helper = require('jsdoc/util/templateHelper'),
-    htmlsafe = helper.htmlsafe,
-    linkto = helper.linkto,
-    resolveAuthorLinks = helper.resolveAuthorLinks,
-    scopeToPunc = helper.scopeToPunc,
-    hasOwnProp = Object.prototype.hasOwnProperty,
-    data,
-    view,
-    outdir = env.opts.destination;
-
-
-function find(spec) {
-    return helper.find(data, spec);
-}
-
-function tutoriallink(tutorial) {
-    return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' });
-}
-
-function getAncestorLinks(doclet) {
-    return helper.getAncestorLinks(data, doclet);
-}
-
-function hashToLink(doclet, hash) {
-    if ( !/^(#.+)/.test(hash) ) { return hash; }
-    
-    var url = helper.createLink(doclet);
-    
-    url = url.replace(/(#.+|$)/, hash);
-    return '<a href="' + url + '">' + hash + '</a>';
-}
-
-function needsSignature(doclet) {
-    var needsSig = false;
-
-    // function and class definitions always get a signature
-    if (doclet.kind === 'function' || doclet.kind === 'class') {
-        needsSig = true;
-    }
-    // typedefs that contain functions get a signature, too
-    else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names &&
-        doclet.type.names.length) {
-        for (var i = 0, l = doclet.type.names.length; i < l; i++) {
-            if (doclet.type.names[i].toLowerCase() === 'function') {
-                needsSig = true;
-                break;
-            }
-        }
-    }
-
-    return needsSig;
-}
-
-function addSignatureParams(f) {
-    var params = helper.getSignatureParams(f, 'optional');
-    
-    f.signature = (f.signature || '') + '('+params.join(', ')+')';
-}
-
-function addSignatureReturns(f) {
-    var returnTypes = helper.getSignatureReturns(f);
-    
-    f.signature = '<span class="signature">'+(f.signature || '') + '</span>' + '<span class="type-signature">'+(returnTypes.length? ' &rarr; {'+returnTypes.join('|')+'}' : '')+'</span>';
-}
-
-function addSignatureTypes(f) {
-    var types = helper.getSignatureTypes(f);
-    
-    f.signature = (f.signature || '') + '<span class="type-signature">'+(types.length? ' :'+types.join('|') : '')+'</span>';
-}
-
-function addAttribs(f) {
-    var attribs = helper.getAttribs(f);
-    
-    f.attribs = '<span class="type-signature">'+htmlsafe(attribs.length? '<'+attribs.join(', ')+'> ' : '')+'</span>';
-}
-
-function shortenPaths(files, commonPrefix) {
-    // always use forward slashes
-    var regexp = new RegExp('\\\\', 'g');
-
-    Object.keys(files).forEach(function(file) {
-        files[file].shortened = files[file].resolved.replace(commonPrefix, '')
-            .replace(regexp, '/');
-    });
-
-    return files;
-}
-
-function resolveSourcePath(filepath) {
-    return path.resolve(process.cwd(), filepath);
-}
-
-function getPathFromDoclet(doclet) {
-    if (!doclet.meta) {
-        return;
-    }
-
-    var filepath = doclet.meta.path && doclet.meta.path !== 'null' ?
-        doclet.meta.path + '/' + doclet.meta.filename :
-        doclet.meta.filename;
-
-    return filepath;
-}
-    
-function generate(title, docs, filename, resolveLinks) {
-    resolveLinks = resolveLinks === false ? false : true;
-
-    var docData = {
-        title: title,
-        docs: docs
-    };
-    
-    var outpath = path.join(outdir, filename),
-        html = view.render('container.tmpl', docData);
-    
-    if (resolveLinks) {
-        html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
-    }
-    
-    fs.writeFileSync(outpath, html, 'utf8');
-}
-
-function generateSourceFiles(sourceFiles) {
-    Object.keys(sourceFiles).forEach(function(file) {
-        var source;
-        // links are keyed to the shortened path in each doclet's `meta.filename` property
-        var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened);
-        helper.registerLink(sourceFiles[file].shortened, sourceOutfile);
-
-        try {
-            source = {
-                kind: 'source',
-                code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, 'utf8') )
-            };
-        }
-        catch(e) {
-            handle(e);
-        }
-
-        generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
-            false);
-    });
-}
-
-/**
- * Look for classes or functions with the same name as modules (which indicates that the module
- * exports only that class or function), then attach the classes or functions to the `module`
- * property of the appropriate module doclets. The name of each class or function is also updated
- * for display purposes. This function mutates the original arrays.
- * 
- * @private
- * @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
- * check.
- * @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
- */
-function attachModuleSymbols(doclets, modules) {
-    var symbols = {};
-
-    // build a lookup table
-    doclets.forEach(function(symbol) {
-        symbols[symbol.longname] = symbol;
-    });
-
-    return modules.map(function(module) {
-        if (symbols[module.longname]) {
-            module.module = symbols[module.longname];
-            module.module.name = module.module.name.replace('module:', 'require("') + '")';
-        }
-    });
-}
-
-/**
- * Create the navigation sidebar.
- * @param {object} members The members that will be used to create the sidebar.
- * @param {array<object>} members.classes
- * @param {array<object>} members.externals
- * @param {array<object>} members.globals
- * @param {array<object>} members.mixins
- * @param {array<object>} members.modules
- * @param {array<object>} members.namespaces
- * @param {array<object>} members.tutorials
- * @param {array<object>} members.events
- * @return {string} The HTML for the navigation sidebar.
- */
-function buildNav(members) {
-    var nav = '<h2><a href="index.html">Index</a></h2>',
-        seen = {},
-        hasClassList = false,
-        classNav = '',
-        globalNav = '';
-
-    if (members.modules.length) {
-        nav += '<h3>Modules</h3><ul>';
-        members.modules.forEach(function(m) {
-            if ( !hasOwnProp.call(seen, m.longname) ) {
-                nav += '<li>'+linkto(m.longname, m.name)+'</li>';
-            }
-            seen[m.longname] = true;
-        });
-        
-        nav += '</ul>';
-    }
-    
-    if (members.externals.length) {
-        nav += '<h3>Externals</h3><ul>';
-        members.externals.forEach(function(e) {
-            if ( !hasOwnProp.call(seen, e.longname) ) {
-                nav += '<li>'+linkto( e.longname, e.name.replace(/(^"|"$)/g, '') )+'</li>';
-            }
-            seen[e.longname] = true;
-        });
-        
-        nav += '</ul>';
-    }
-
-    if (members.classes.length) {
-        members.classes.forEach(function(c) {
-            if ( !hasOwnProp.call(seen, c.longname) ) {
-                classNav += '<li>'+linkto(c.longname, c.name)+'</li>';
-            }
-            seen[c.longname] = true;
-        });
-        
-        if (classNav !== '') {
-            nav += '<h3>Classes</h3><ul>';
-            nav += classNav;
-            nav += '</ul>';
-        }
-    }
-
-    if (members.events.length) {
-        nav += '<h3>Events</h3><ul>';
-        members.events.forEach(function(e) {
-            if ( !hasOwnProp.call(seen, e.longname) ) {
-                nav += '<li>'+linkto(e.longname, e.name)+'</li>';
-            }
-            seen[e.longname] = true;
-        });
-        
-        nav += '</ul>';
-    }
-    
-    if (members.namespaces.length) {
-        nav += '<h3>Namespaces</h3><ul>';
-        members.namespaces.forEach(function(n) {
-            if ( !hasOwnProp.call(seen, n.longname) ) {
-                nav += '<li>'+linkto(n.longname, n.name)+'</li>';
-            }
-            seen[n.longname] = true;
-        });
-        
-        nav += '</ul>';
-    }
-    
-    if (members.mixins.length) {
-        nav += '<h3>Mixins</h3><ul>';
-        members.mixins.forEach(function(m) {
-            if ( !hasOwnProp.call(seen, m.longname) ) {
-                nav += '<li>'+linkto(m.longname, m.name)+'</li>';
-            }
-            seen[m.longname] = true;
-        });
-        
-        nav += '</ul>';
-    }
-
-    if (members.tutorials.length) {
-        nav += '<h3>Tutorials</h3><ul>';
-        members.tutorials.forEach(function(t) {
-            nav += '<li>'+tutoriallink(t.name)+'</li>';
-        });
-        
-        nav += '</ul>';
-    }
-    
-    if (members.globals.length) {
-        members.globals.forEach(function(g) {
-            if ( g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname) ) {
-                globalNav += '<li>' + linkto(g.longname, g.name) + '</li>';
-            }
-            seen[g.longname] = true;
-        });
-        
-        if (!globalNav) {
-            // turn the heading into a link so you can actually get to the global page
-            nav += '<h3>' + linkto('global', 'Global') + '</h3>';
-        }
-        else {
-            nav += '<h3>Global</h3><ul>' + globalNav + '</ul>';
-        }
-    }
-
-    return nav;
-}
-
-
-/**
-    @param {TAFFY} taffyData See <http://taffydb.com/>.
-    @param {object} opts
-    @param {Tutorial} tutorials
- */
-exports.publish = function(taffyData, opts, tutorials) {
-    data = taffyData;
-
-    var conf = env.conf.templates || {};
-    conf['default'] = conf['default'] || {};
-
-    var templatePath = opts.template;
-    view = new template.Template(templatePath + '/tmpl');
-    
-    // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
-    // doesn't try to hand them out later
-    var indexUrl = helper.getUniqueFilename('index');
-    // don't call registerLink() on this one! 'index' is also a valid longname
-
-    var globalUrl = helper.getUniqueFilename('global');
-    helper.registerLink('global', globalUrl);
-
-    // set up templating
-    view.layout = 'layout.tmpl';
-
-    // set up tutorials for helper
-    helper.setTutorials(tutorials);
-
-    data = helper.prune(data);
-    data.sort('longname, version, since');
-    helper.addEventListeners(data);
-
-    var sourceFiles = {};
-    var sourceFilePaths = [];
-    data().each(function(doclet) {
-         doclet.attribs = '';
-        
-        if (doclet.examples) {
-            doclet.examples = doclet.examples.map(function(example) {
-                var caption, code;
-                
-                if (example.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) {
-                    caption = RegExp.$1;
-                    code    = RegExp.$3;
-                }
-                
-                return {
-                    caption: caption || '',
-                    code: code || example
-                };
-            });
-        }
-        if (doclet.see) {
-            doclet.see.forEach(function(seeItem, i) {
-                doclet.see[i] = hashToLink(doclet, seeItem);
-            });
-        }
-
-        // build a list of source files
-        var sourcePath;
-        var resolvedSourcePath;
-        if (doclet.meta) {
-            sourcePath = getPathFromDoclet(doclet);
-            resolvedSourcePath = resolveSourcePath(sourcePath);
-            sourceFiles[sourcePath] = {
-                resolved: resolvedSourcePath,
-                shortened: null
-            };
-            sourceFilePaths.push(resolvedSourcePath);
-        }
-    });
-    
-    // update outdir if necessary, then create outdir
-    var packageInfo = ( find({kind: 'package'}) || [] ) [0];
-    if (packageInfo && packageInfo.name) {
-        outdir = path.join(outdir, packageInfo.name, packageInfo.version);
-    }
-    fs.mkPath(outdir);
-
-    // copy the template's static files to outdir
-    var fromDir = path.join(templatePath, 'static');
-    var staticFiles = fs.ls(fromDir, 3);
-
-    staticFiles.forEach(function(fileName) {
-        var toDir = fs.toDir( fileName.replace(fromDir, outdir) );
-        fs.mkPath(toDir);
-        fs.copyFileSync(fileName, toDir);
-    });
-
-    // copy user-specified static files to outdir
-    var staticFilePaths;
-    var staticFileFilter;
-    var staticFileScanner;
-    if (conf['default'].staticFiles) {
-        staticFilePaths = conf['default'].staticFiles.paths || [];
-        staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf['default'].staticFiles);
-        staticFileScanner = new (require('jsdoc/src/scanner')).Scanner();
-
-        staticFilePaths.forEach(function(filePath) {
-            var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter);
-
-            extraStaticFiles.forEach(function(fileName) {
-                var sourcePath = fs.statSync(filePath).isDirectory() ? filePath :
-                    path.dirname(filePath);
-                var toDir = fs.toDir( fileName.replace(sourcePath, outdir) );
-                fs.mkPath(toDir);
-                fs.copyFileSync(fileName, toDir);
-            });
-        });
-    }
-    
-    if (sourceFilePaths.length) {
-        sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) );
-    }
-    data().each(function(doclet) {
-        var url = helper.createLink(doclet);
-        helper.registerLink(doclet.longname, url);
-
-        // replace the filename with a shortened version of the full path
-        var docletPath;
-        if (doclet.meta) {
-            docletPath = getPathFromDoclet(doclet);
-            docletPath = sourceFiles[docletPath].shortened;
-            if (docletPath) {
-                doclet.meta.filename = docletPath;
-            }
-        }
-    });
-    
-    data().each(function(doclet) {
-        var url = helper.longnameToUrl[doclet.longname];
-
-        if (url.indexOf('#') > -1) {
-            doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop();
-        }
-        else {
-            doclet.id = doclet.name;
-        }
-        
-        if ( needsSignature(doclet) ) {
-            addSignatureParams(doclet);
-            addSignatureReturns(doclet);
-            addAttribs(doclet);
-        }
-    });
-    
-    // do this after the urls have all been generated
-    data().each(function(doclet) {
-        doclet.ancestors = getAncestorLinks(doclet);
-
-        if (doclet.kind === 'member') {
-            addSignatureTypes(doclet);
-            addAttribs(doclet);
-        }
-        
-        if (doclet.kind === 'constant') {
-            addSignatureTypes(doclet);
-            addAttribs(doclet);
-            doclet.kind = 'member';
-        }
-    });
-    
-    var members = helper.getMembers(data);
-    members.tutorials = tutorials.children;
-
-    // add template helpers
-    view.find = find;
-    view.linkto = linkto;
-    view.resolveAuthorLinks = resolveAuthorLinks;
-    view.tutoriallink = tutoriallink;
-    view.htmlsafe = htmlsafe;
-
-    // once for all
-    view.nav = buildNav(members);
-    attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }),
-        members.modules );
-
-    // only output pretty-printed source files if requested; do this before generating any other
-    // pages, so the other pages can link to the source files
-    if (conf['default'].outputSourceFiles) {
-        generateSourceFiles(sourceFiles);
-    }
-
-    if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); }
-    
-    // index page displays information from package.json and lists files
-    var files = find({kind: 'file'}),
-        packages = find({kind: 'package'});
-
-    generate('Index',
-        packages.concat(
-            [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]
-        ).concat(files),
-    indexUrl);
-
-    // set up the lists that we'll use to generate pages
-    var classes = taffy(members.classes);
-    var modules = taffy(members.modules);
-    var namespaces = taffy(members.namespaces);
-    var mixins = taffy(members.mixins);
-    var externals = taffy(members.externals);
-    
-    Object.keys(helper.longnameToUrl).forEach(function(longname) {
-        var myClasses = helper.find(classes, {longname: longname});
-        if (myClasses.length) {
-            generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]);
-        }
-        
-        var myModules = helper.find(modules, {longname: longname});
-        if (myModules.length) {
-            generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]);
-        }
-
-        var myNamespaces = helper.find(namespaces, {longname: longname});
-        if (myNamespaces.length) {
-            generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]);
-        }
-        
-        var myMixins = helper.find(mixins, {longname: longname});
-        if (myMixins.length) {
-            generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]);
-        }
-
-        var myExternals = helper.find(externals, {longname: longname});
-        if (myExternals.length) {
-            generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]);
-        }
-    });
-
-    // TODO: move the tutorial functions to templateHelper.js
-    function generateTutorial(title, tutorial, filename) {
-        var tutorialData = {
-            title: title,
-            header: tutorial.title,
-            content: tutorial.parse(),
-            children: tutorial.children
-        };
-        
-        var tutorialPath = path.join(outdir, filename),
-            html = view.render('tutorial.tmpl', tutorialData);
-        
-        // yes, you can use {@link} in tutorials too!
-        html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
-        
-        fs.writeFileSync(tutorialPath, html, 'utf8');
-    }
-    
-    // tutorials can have only one parent so there is no risk for loops
-    function saveChildren(node) {
-        node.children.forEach(function(child) {
-            generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name));
-            saveChildren(child);
-        });
-    }
-    saveChildren(tutorials);
-};
diff --git a/scripts/templates/xtuple/static/scripts/linenumber.js b/scripts/templates/xtuple/static/scripts/linenumber.js
deleted file mode 100644 (file)
index a0c570d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-(function() {
-    var counter = 0;
-    var numbered;
-    var source = document.getElementsByClassName('prettyprint source');
-
-    if (source && source[0]) {
-        source = source[0].getElementsByTagName('code')[0];
-
-        numbered = source.innerHTML.split('\n');
-        numbered = numbered.map(function(item) {
-            counter++;
-            return '<span id="line' + counter + '"></span>' + item;
-        });
-
-        source.innerHTML = numbered.join('\n');
-    }
-})();
diff --git a/scripts/templates/xtuple/static/scripts/prettify/Apache-License-2.0.txt b/scripts/templates/xtuple/static/scripts/prettify/Apache-License-2.0.txt
deleted file mode 100644 (file)
index d645695..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/scripts/templates/xtuple/static/scripts/prettify/lang-css.js b/scripts/templates/xtuple/static/scripts/prettify/lang-css.js
deleted file mode 100644 (file)
index 041e1f5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n\f"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
-/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
diff --git a/scripts/templates/xtuple/static/scripts/prettify/prettify.js b/scripts/templates/xtuple/static/scripts/prettify/prettify.js
deleted file mode 100644 (file)
index eef5ad7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
-(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
-[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
-f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
-(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
-{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
-t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
-"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
-l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
-q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
-q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
-"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
-a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
-for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
-m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
-a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
-j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
-"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
-H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
-J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
-I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
-["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
-/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
-["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
-hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
-!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
-250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
-PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
diff --git a/scripts/templates/xtuple/static/styles/jsdoc-default.css b/scripts/templates/xtuple/static/styles/jsdoc-default.css
deleted file mode 100644 (file)
index ea49f60..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-html
-{
-    overflow: auto;
-    background-color: #fff;
-}
-
-body
-{
-       font: 14px "DejaVu Sans Condensed", "Liberation Sans", "Nimbus Sans L", Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans serif;
-       line-height: 130%;
-       color: #000;
-       background-color: #fff;
-}
-
-a {
-    color: #444;
-}
-
-a:visited {
-    color: #444;
-}
-
-a:active {
-    color: #444;
-}
-
-header
-{
-       display: block;
-       padding: 6px 4px;
-}
-
-.class-description {
-    font-style: italic;
-       font-family: Palatino, 'Palatino Linotype', serif;
-       font-size: 130%;
-       line-height: 140%;
-       margin-bottom: 1em;
-       margin-top: 1em;
-}
-
-#main {
-    float: left;
-    width: 100%;
-}
-
-section
-{
-       display: block;
-       
-       background-color: #fff;
-       padding: 12px 24px;
-    border-bottom: 1px solid #ccc;
-    margin-right: 240px;
-}
-
-.variation {
-    display: none;
-}
-
-.optional:after {
-       content: "opt";
-       font-size: 60%;
-       color: #aaa;
-       font-style: italic;
-       font-weight: lighter;
-}
-
-nav
-{
-       display: block;
-       float: left;
-    margin-left: -230px;
-    margin-top: 28px;
-    width: 220px;
-    border-left: 1px solid #ccc;
-    padding-left: 9px;
-}
-
-nav ul {
-    font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif;
-    font-size: 100%;
-    line-height: 17px;
-    padding:0;
-    margin:0;
-    list-style-type:none;
-}
-
-nav h2 a, nav h2 a:visited {
-    color: #A35A00;
-    text-decoration: none;
-}
-
-nav h3 {
-    margin-top: 12px;
-}
-
-nav li {
-    margin-top: 6px;
-}
-
-nav a {
-    color: #5C5954;
-}
-
-nav a:visited {
-    color: #5C5954;
-}
-
-nav a:active {
-    color: #5C5954;
-}
-
-footer {
-    display: block;
-    padding: 6px;
-    margin-top: 12px;
-    font-style: italic;
-    font-size: 90%;
-}
-
-h1
-{
-       font-size: 200%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 6px 0 9px 0;
-}
-
-h2
-{
-       font-size: 170%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 6px 0 3px 0;
-}
-
-h3
-{
-       font-size: 150%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin-top: 16px;
-       margin: 6px 0 3px 0;
-}
-
-h4
-{
-       font-size: 130%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin-top: 16px;
-       margin: 18px 0 3px 0;
-       color: #A35A00;
-}
-
-h5, .container-overview .subsection-title
-{
-       font-size: 120%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 8px 0 3px -16px;
-}
-
-h6
-{
-       font-size: 100%;
-       letter-spacing: -0.01em;
-       margin: 6px 0 3px 0;
-       font-style: italic;
-}
-
-.ancestors { color: #999; }
-.ancestors a
-{
-    color: #999 !important;
-    text-decoration: none;
-}
-
-.important
-{
-       font-weight: bold;
-       color: #950B02;
-}
-
-.yes-def {
-    text-indent: -1000px;
-}
-
-.type-signature {
-    color: #aaa;
-}
-
-.name, .signature {
-       font-family: Consolas, "Lucida Console", Monaco, monospace;
-}
-
-.details { margin-top: 14px; }
-.details dt { width:100px; float:left; border-left: 2px solid #DDD; padding-left: 10px;  padding-top: 6px; }
-.details dd { margin-left: 50px; }
-.details ul { margin: 0; }
-.details ul { list-style-type: none; }
-.details li { margin-left: 30px; padding-top: 6px; }
-
-.description {
-       margin-bottom: 1em;
-       margin-left: -16px;
-       margin-top: 1em;
-}
-
-.code-caption
-{
-       font-style: italic;
-       font-family: Palatino, 'Palatino Linotype', serif;
-       font-size: 107%;
-       margin: 0;
-}
-
-.prettyprint
-{
-       border: 1px solid #ddd;
-       width: 80%;
-    overflow: auto;
-}
-
-.prettyprint.source {
-    width: inherit;
-}
-
-.prettyprint code
-{
-       font-family: Consolas, 'Lucida Console', Monaco, monospace;
-       font-size: 100%;
-       line-height: 18px;
-       display: block;
-       padding: 4px 12px;
-       margin: 0;
-       background-color: #fff;
-       color: #000;
-       border-left: 3px #ddd solid;
-}
-
-.params, .props
-{
-       border-spacing: 0;
-       border: 0;
-       border-collapse: collapse;
-}
-
-.params .name, .props .name, .name code {
-       color: #A35A00;
-       font-family: Consolas, 'Lucida Console', Monaco, monospace;
-       font-size: 100%;
-}
-
-.params td, .params th, .props td, .props th
-{
-       border: 1px solid #ddd;
-       margin: 0px;
-       text-align: left;
-       vertical-align: top;
-       padding: 4px 6px;
-       display: table-cell;
-}
-
-.params thead tr, .props thead tr
-{
-       background-color: #ddd;
-       font-weight: bold;
-}
-
-.params .params thead tr, .props .props thead tr
-{
-       background-color: #fff;
-       font-weight: bold;
-}
-
-.params th, .props th { border-right: 1px solid #aaa; }
-.params thead .last, .props thead .last { border-right: 1px solid #ddd; }
-
-.disabled {
-    color: #454545;
-}
diff --git a/scripts/templates/xtuple/static/styles/prettify-jsdoc.css b/scripts/templates/xtuple/static/styles/prettify-jsdoc.css
deleted file mode 100644 (file)
index 5a2526e..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* JSDoc prettify.js theme */
-
-/* plain text */
-.pln {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* string content */
-.str {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a keyword */
-.kwd {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a comment */
-.com {
-  font-weight: normal;
-  font-style: italic;
-}
-
-/* a type name */
-.typ {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a literal value */
-.lit {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* punctuation */
-.pun {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* lisp open bracket */
-.opn {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* lisp close bracket */
-.clo {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a markup tag name */
-.tag {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a markup attribute name */
-.atn {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a markup attribute value */
-.atv {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a declaration */
-.dec {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a variable name */
-.var {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a function name */
-.fun {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* Specify class=linenums on a pre to get line numbering */
-ol.linenums {
-  margin-top: 0;
-  margin-bottom: 0;
-}
diff --git a/scripts/templates/xtuple/static/styles/prettify-tomorrow.css b/scripts/templates/xtuple/static/styles/prettify-tomorrow.css
deleted file mode 100644 (file)
index aa2908c..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Tomorrow Theme */
-/* Original theme - https://github.com/chriskempson/tomorrow-theme */
-/* Pretty printing styles. Used with prettify.js. */
-/* SPAN elements with the classes below are added by prettyprint. */
-/* plain text */
-.pln {
-  color: #4d4d4c; }
-
-@media screen {
-  /* string content */
-  .str {
-    color: #718c00; }
-
-  /* a keyword */
-  .kwd {
-    color: #8959a8; }
-
-  /* a comment */
-  .com {
-    color: #8e908c; }
-
-  /* a type name */
-  .typ {
-    color: #4271ae; }
-
-  /* a literal value */
-  .lit {
-    color: #f5871f; }
-
-  /* punctuation */
-  .pun {
-    color: #4d4d4c; }
-
-  /* lisp open bracket */
-  .opn {
-    color: #4d4d4c; }
-
-  /* lisp close bracket */
-  .clo {
-    color: #4d4d4c; }
-
-  /* a markup tag name */
-  .tag {
-    color: #c82829; }
-
-  /* a markup attribute name */
-  .atn {
-    color: #f5871f; }
-
-  /* a markup attribute value */
-  .atv {
-    color: #3e999f; }
-
-  /* a declaration */
-  .dec {
-    color: #f5871f; }
-
-  /* a variable name */
-  .var {
-    color: #c82829; }
-
-  /* a function name */
-  .fun {
-    color: #4271ae; } }
-/* Use higher contrast and text-weight for printable form. */
-@media print, projection {
-  .str {
-    color: #060; }
-
-  .kwd {
-    color: #006;
-    font-weight: bold; }
-
-  .com {
-    color: #600;
-    font-style: italic; }
-
-  .typ {
-    color: #404;
-    font-weight: bold; }
-
-  .lit {
-    color: #044; }
-
-  .pun, .opn, .clo {
-    color: #440; }
-
-  .tag {
-    color: #006;
-    font-weight: bold; }
-
-  .atn {
-    color: #404; }
-
-  .atv {
-    color: #060; } }
-/* Style */
-/*
-pre.prettyprint {
-  background: white;
-  font-family: Menlo, Monaco, Consolas, monospace;
-  font-size: 12px;
-  line-height: 1.5;
-  border: 1px solid #ccc;
-  padding: 10px; }
-*/
-
-/* Specify class=linenums on a pre to get line numbering */
-ol.linenums {
-  margin-top: 0;
-  margin-bottom: 0; }
-
-/* IE indents via margin-left */
-li.L0,
-li.L1,
-li.L2,
-li.L3,
-li.L4,
-li.L5,
-li.L6,
-li.L7,
-li.L8,
-li.L9 {
-  /* */ }
-
-/* Alternate shading for lines */
-li.L1,
-li.L3,
-li.L5,
-li.L7,
-li.L9 {
-  /* */ }
diff --git a/scripts/templates/xtuple/tmpl/container.tmpl b/scripts/templates/xtuple/tmpl/container.tmpl
deleted file mode 100644 (file)
index 6bdf257..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-<?js
-    var self = this;
-    docs.forEach(function(doc, i) {
-?>
-
-<?js if (doc.kind === 'mainpage' || (doc.kind === 'package')) { ?>
-    <?js= self.partial('mainpage.tmpl', doc) ?>
-<?js } else if (doc.kind === 'source') { ?>
-    <?js= self.partial('source.tmpl', doc) ?>
-<?js } else { ?>
-
-<section>
-    
-<header>
-    <h2><?js if (doc.ancestors && doc.ancestors.length) { ?>
-        <span class="ancestors"><?js= doc.ancestors.join('') ?></span>
-    <?js } ?>
-    <?js= doc.name ?>
-    <?js if (doc.variation) { ?>
-        <sup class="variation"><?js= doc.variation ?></sup>
-    <?js } ?></h2>
-    <?js if (doc.classdesc) { ?>
-        <div class="class-description"><?js= doc.classdesc ?></div>
-    <?js } ?>
-</header>  
-
-<article>
-    <div class="container-overview">
-    <?js if (doc.kind === 'module' && doc.module) { ?>
-        <?js= self.partial('method.tmpl', doc.module) ?>
-    <?js } ?>
-    
-    <?js if (doc.kind === 'class') { ?>
-        <?js= self.partial('method.tmpl', doc) ?>
-    <?js } else { ?>
-        <?js if (doc.description) { ?>
-            <div class="description"><?js= doc.description ?></div>
-        <?js } ?>
-        
-        <?js= self.partial('details.tmpl', doc) ?>
-        
-        <?js if (doc.examples && doc.examples.length) { ?>
-            <h3>Example<?js= doc.examples.length > 1? 's':'' ?></h3>
-            <?js= self.partial('examples.tmpl', doc.examples) ?>
-        <?js } ?>
-    <?js } ?>
-    </div>
-    
-    <?js if (doc.augments && doc.augments.length) { ?>
-        <h3 class="subsection-title">Extends</h3>
-        
-        <ul><?js doc.augments.forEach(function(a) { ?>
-            <li><?js= self.linkto(a, a) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (doc.mixes && doc.mixes.length) { ?>
-        <h3 class="subsection-title">Mixes In</h3>
-        
-        <ul><?js doc.mixes.forEach(function(a) { ?>
-            <li><?js= self.linkto(a, a) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (doc.requires && doc.requires.length) { ?>
-        <h3 class="subsection-title">Requires</h3>
-        
-        <ul><?js doc.requires.forEach(function(r) { ?>
-            <li><?js= self.linkto(r, r) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js
-        var namespaces = self.find({kind: 'namespace', memberof: doc.longname}); 
-        if (doc.kind !== 'globalobj' && namespaces && namespaces.length) { 
-    ?>
-        <h3 class="subsection-title">Namesplaces</h3>
-        
-        <dl><?js namespaces.forEach(function(n) { ?>
-            <dt><a href="namespaces.html#<?js= n.longname ?>"><?js= self.linkto(n.longname, n.name) ?></a></dt>
-            <dd><?js if (n.summary) { ?><?js= n.summary ?><?js } ?></dd>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var classes = self.find({kind: 'class', memberof: doc.longname}); 
-        if (doc.kind !== 'globalobj' && classes && classes.length) { 
-    ?>
-        <h3 class="subsection-title">Classes</h3>
-        
-        <dl><?js classes.forEach(function(c) { ?>
-            <dt><?js= self.linkto(c.longname, c.longname) ?></dt>
-            <dd><?js if (c.summary) { ?><?js= c.summary ?><?js } ?></dd>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var members = self.find({kind: 'member', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
-        if (members && members.length && members.forEach) { 
-    ?>
-        <h3 class="subsection-title">Members</h3>
-        
-        <dl><?js members.forEach(function(p) { ?>
-            <?js= self.partial('members.tmpl', p) ?>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var methods = self.find({kind: 'function', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
-        if (methods && methods.length && methods.forEach) { 
-    ?>
-        <h3 class="subsection-title">Methods</h3>
-        
-        <dl><?js methods.forEach(function(m) { ?>
-            <?js= self.partial('method.tmpl', m) ?>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var typedefs = self.find({kind: 'typedef', memberof: title === 'Global' ? {isUndefined: true} : doc.longname}); 
-        if (typedefs && typedefs.length && typedefs.forEach) { 
-    ?>
-        <h3 class="subsection-title">Type Definitions</h3>
-        
-        <dl><?js typedefs.forEach(function(e) {
-                if (e.signature) {
-            ?>
-                <?js= self.partial('method.tmpl', e) ?>
-            <?js
-                }
-                else {
-            ?>
-                <?js= self.partial('members.tmpl', e) ?>
-            <?js
-                }
-            }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var events = self.find({kind: 'event', memberof: title === 'Global' ? {isUndefined: true} : doc.longname}); 
-        if (events && events.length && events.forEach) { 
-    ?>
-        <h3 class="subsection-title">Events</h3>
-        
-        <dl><?js events.forEach(function(e) { ?>
-            <?js= self.partial('method.tmpl', e) ?>
-        <?js }); ?></dl>
-    <?js } ?>
-</article>
-
-</section>  
-<?js } ?>
-
-<?js }); ?>
diff --git a/scripts/templates/xtuple/tmpl/details.tmpl b/scripts/templates/xtuple/tmpl/details.tmpl
deleted file mode 100644 (file)
index d3b3552..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dl class="details">
-    <?js
-        var properties = data.properties;
-        if (properties && properties.length && properties.forEach) { 
-    ?>
-        
-        <h5 class="subsection-title">Properties:</h5>
-        
-        <dl><?js= this.partial('properties.tmpl', properties) ?></dl>
-        
-    <?js } ?>
-        
-    <?js if (data.version) {?>
-    <dt class="tag-version">Version:</dt>
-    <dd class="tag-version"><ul class="dummy"><li><?js= version ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.since) {?>
-    <dt class="tag-since">Since:</dt>
-    <dd class="tag-since"><ul class="dummy"><li><?js= since ?></dd>
-    <?js } ?>
-
-    <?js if (data.inherited && data.inherits) { ?>
-    <dt class="inherited-from">Inherited From:</dt>
-    <dd class="inherited-from"><ul class="dummy"><li>
-        <?js= this.linkto(data.inherits, this.htmlsafe(data.inherits)) ?>
-    </li></dd>
-    <?js } ?>
-    
-    <?js if (data.deprecated) { ?>
-        <dt class="important tag-deprecated">Deprecated:</dt><?js
-            if (data.deprecated === true) { ?><dd class="yes-def tag-deprecated"><ul class="dummy"><li>Yes</li></ul></dd><?js }
-            else { ?><dd><ul class="dummy"><li><?js= data.deprecated ?></li><ul></dd><?js }
-        ?>
-    <?js } ?>
-    
-    <?js if (data.author && author.length) {?>
-    <dt class="tag-author">Author:</dt>
-    <dd class="tag-author">
-        <ul><?js author.forEach(function(a) { ?>
-            <li><?js= self.resolveAuthorLinks(a) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.copyright) {?>
-    <dt class="tag-copyright">Copyright:</dt>
-    <dd class="tag-copyright"><ul class="dummy"><li><?js= copyright ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.license) {?>
-    <dt class="tag-license">License:</dt>
-    <dd class="tag-license"><ul class="dummy"><li><?js= license ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.defaultvalue) {?>
-    <dt class="tag-default">Default Value:</dt>
-    <dd class="tag-default"><ul class="dummy"><li><?js= data.defaultvalue ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.meta) {?>
-    <dt class="tag-source">Source:</dt>
-    <dd class="tag-source"><ul class="dummy"><li>
-        <?js= self.linkto(meta.filename) ?>, <?js= self.linkto(meta.filename, 'line ' + meta.lineno, null, 'line' + meta.lineno) ?>
-    </li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.tutorials && tutorials.length) {?>
-    <dt class="tag-tutorial">Tutorials:</dt>
-    <dd class="tag-tutorial">
-        <ul><?js tutorials.forEach(function(t) { ?>
-            <li><?js= self.tutoriallink(t) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.see && see.length) {?>
-    <dt class="tag-see">See:</dt>
-    <dd class="tag-see">
-        <ul><?js see.forEach(function(s) { ?>
-            <li><?js= self.linkto(s) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.todo && todo.length) {?>
-    <dt class="tag-todo">To Do:</dt>
-    <dd class="tag-todo">
-        <ul><?js todo.forEach(function(t) { ?>
-            <li><?js= t ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-</dl>
diff --git a/scripts/templates/xtuple/tmpl/example.tmpl b/scripts/templates/xtuple/tmpl/example.tmpl
deleted file mode 100644 (file)
index e87caa5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<?js var data = obj; ?>
-<pre><code><?js= data ?></code></pre>
diff --git a/scripts/templates/xtuple/tmpl/examples.tmpl b/scripts/templates/xtuple/tmpl/examples.tmpl
deleted file mode 100644 (file)
index 23384c9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?js
-       var data = obj;
-    data.forEach(function(example) {
-        if (example.caption) {
-    ?>
-        <p class="code-caption"><?js= example.caption ?></p>
-    <?js } ?>
-    <pre class="prettyprint"><code><?js= example.code ?></code></pre>
-<?js
-    });
-?>
\ No newline at end of file
diff --git a/scripts/templates/xtuple/tmpl/exceptions.tmpl b/scripts/templates/xtuple/tmpl/exceptions.tmpl
deleted file mode 100644 (file)
index 78c4e25..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?js
-    var data = obj;
-?>
-<?js if (data.description && data.type && data.type.names) { ?>
-<dl>
-    <dt>
-        <div class="param-desc">
-        <?js= data.description ?>
-        </div>
-    </dt>
-    <dt>
-        <dl>
-            <dt>
-                Type
-            </dt>
-            <dd>
-                <?js= this.partial('type.tmpl', data.type.names) ?>
-            </dd>
-        </dl>
-    </dt>
-</dl>
-<?js } else { ?>
-    <div class="param-desc">
-    <?js if (data.description) { ?>
-        <?js= data.description ?>
-    <?js } else if (data.type && data.type.names) { ?>
-        <?js= this.partial('type.tmpl', data.type.names) ?>
-    <?js } ?>
-    </div>
-<?js } ?>
diff --git a/scripts/templates/xtuple/tmpl/layout.tmpl b/scripts/templates/xtuple/tmpl/layout.tmpl
deleted file mode 100644 (file)
index 827b5ac..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <title>JSDoc: <?js= title ?></title>
-    
-    <script src="scripts/prettify/prettify.js"> </script>
-    <script src="scripts/prettify/lang-css.js"> </script>
-    <!--[if lt IE 9]>
-      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
-    <![endif]-->
-    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
-    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
-</head>
-
-<body>
-
-<div id="main">
-    
-    <h1 class="page-title"><?js= title ?></h1>
-    
-    <?js= content ?>
-</div>
-
-<nav>
-    <?js= this.nav ?>
-</nav>
-
-<br clear="both">
-
-<footer>
-    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc <?js= env.version.number ?></a> on <?js= (new Date()) ?>
-</footer>
-
-<script> prettyPrint(); </script>
-<script src="scripts/linenumber.js"> </script>
-</body>
-</html>
diff --git a/scripts/templates/xtuple/tmpl/mainpage.tmpl b/scripts/templates/xtuple/tmpl/mainpage.tmpl
deleted file mode 100644 (file)
index 64e9e59..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-
-<?js if (data.kind === 'package') { ?>
-    <h3><?js= data.name ?> <?js= data.version ?></h3>
-<?js } ?>
-
-<?js if (data.readme) { ?>
-    <section>
-        <article><?js= data.readme ?></article>
-    </section>
-<?js } ?>
diff --git a/scripts/templates/xtuple/tmpl/members.tmpl b/scripts/templates/xtuple/tmpl/members.tmpl
deleted file mode 100644 (file)
index 3fded71..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dt>
-    <h4 class="name" id="<?js= id ?>"><?js= data.attribs + name + (data.signature ? data.signature : '') ?></h4>
-    
-    <?js if (data.summary) { ?>
-    <p class="summary"><?js= summary ?></p>
-    <?js } ?>
-</dt>
-<dd>
-    <?js if (data.description) { ?>
-    <div class="description">
-        <?js= data.description ?>
-    </div>
-    <?js } ?>
-    
-    <?js if (data.type && data.type.names) {?>
-        <h5>Type:</h5>
-        <ul>
-            <li>
-                <?js= self.partial('type.tmpl', data.type.names) ?>
-            </li>
-        </ul>
-    <?js } ?>
-
-    <?js= this.partial('details.tmpl', data) ?>
-    
-    <?js if (data.examples && examples.length) { ?>
-        <h5>Example<?js= examples.length > 1? 's':'' ?></h5>
-        <?js= this.partial('examples.tmpl', examples) ?>
-    <?js } ?>
-</dd>
diff --git a/scripts/templates/xtuple/tmpl/method.tmpl b/scripts/templates/xtuple/tmpl/method.tmpl
deleted file mode 100644 (file)
index 1fff9b8..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dt>
-    <h4 class="name" id="<?js= id ?>"><?js= data.attribs + (kind === 'class' ? 'new ' : '') + name + (kind !== 'event' ? data.signature : '') ?></h4>
-    
-    <?js if (data.summary) { ?>
-    <p class="summary"><?js= summary ?></p>
-    <?js } ?>
-</dt>
-<dd>
-    
-    <?js if (data.description) { ?>
-    <div class="description">
-        <?js= data.description ?>
-    </div>
-    <?js } ?>
-
-    <?js if (kind === 'event' && data.type && data.type.names) {?>
-        <h5>Type:</h5>
-        <ul>
-            <li>
-                <?js= self.partial('type.tmpl', data.type.names) ?>
-            </li>
-        </ul>
-    <?js } ?>
-    
-    <?js if (data['this']) { ?>
-        <h5>This:</h5>
-        <ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
-    <?js } ?>
-    
-    <?js if (data.params && params.length) { ?>
-        <h5>Parameters:</h5>
-        <?js= this.partial('params.tmpl', params) ?>
-    <?js } ?>
-    
-    <?js= this.partial('details.tmpl', data) ?>
-    
-    <?js if (data.fires && fires.length) { ?>
-    <h5>Fires:</h5>
-    <ul><?js fires.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <?js if (data.listens && listens.length) { ?>
-    <h5>Listens to Events:</h5>
-    <ul><?js listens.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <?js if (data.listeners && listeners.length) { ?>
-    <h5>Listeners of This Event:</h5>
-    <ul><?js listeners.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (data.exceptions && exceptions.length) { ?>
-    <h5>Throws:</h5>
-    <?js if (exceptions.length > 1) { ?><ul><?js
-        exceptions.forEach(function(r) { ?>
-            <li><?js= self.partial('exceptions.tmpl', r) ?></li>
-        <?js });
-    ?></ul><?js } else {
-        exceptions.forEach(function(r) { ?>
-            <?js= self.partial('exceptions.tmpl', r) ?>
-        <?js });
-    } } ?>
-    
-    <?js if (data.returns && returns.length) { ?>
-    <h5>Returns:</h5>
-    <?js if (returns.length > 1) { ?><ul><?js
-        returns.forEach(function(r) { ?>
-            <li><?js= self.partial('returns.tmpl', r) ?></li>
-        <?js });
-    ?></ul><?js } else {
-        returns.forEach(function(r) { ?>
-            <?js= self.partial('returns.tmpl', r) ?>
-        <?js });
-    } } ?>
-    
-    <?js if (data.examples && examples.length) { ?>
-        <h5>Example<?js= examples.length > 1? 's':'' ?></h5>
-        <?js= this.partial('examples.tmpl', examples) ?>
-    <?js } ?>
-</dd>
diff --git a/scripts/templates/xtuple/tmpl/params.tmpl b/scripts/templates/xtuple/tmpl/params.tmpl
deleted file mode 100644 (file)
index 7b95114..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<?js
-    var params = obj;
-    
-    /* sort subparams under their parent params (like opts.classname) */
-    var parentParam = null;
-    params.forEach(function(param, i) {
-        if (!param) { return; }
-        if ( parentParam && param.name && param.name.indexOf(parentParam.name + '.') === 0 ) {
-            param.name = param.name.substr(parentParam.name.length+1);
-            parentParam.subparams = parentParam.subparams || [];
-            parentParam.subparams.push(param);
-            params[i] = null;
-        }
-        else {
-            parentParam = param;
-        }
-    });
-    
-    /* determine if we need extra columns, "attributes" and "default" */
-    params.hasAttributes = false;
-    params.hasDefault = false;
-    params.hasName = false;
-    
-    params.forEach(function(param) {
-        if (!param) { return; }
-        
-        if (param.optional || param.nullable || param.variable) {
-            params.hasAttributes = true;
-        }
-        
-        if (param.name) {
-            params.hasName = true;
-        }
-        
-        if (typeof param.defaultvalue !== 'undefined') {
-            params.hasDefault = true;
-        }
-    });
-?>
-
-<table class="params">
-    <thead>
-       <tr>
-               <?js if (params.hasName) {?>
-               <th>Name</th>
-               <?js } ?>
-               
-               <th>Type</th>
-               
-               <?js if (params.hasAttributes) {?>
-               <th>Argument</th>
-               <?js } ?>
-               
-               <?js if (params.hasDefault) {?>
-               <th>Default</th>
-               <?js } ?>
-               
-               <th class="last">Description</th>
-       </tr>
-       </thead>
-       
-       <tbody>
-       <?js
-        var self = this;
-           params.forEach(function(param) {
-               if (!param) { return; }
-       ?>
-       
-        <tr>
-            <?js if (params.hasName) {?>
-                <td class="name"><code><?js= param.name ?></code></td>
-            <?js } ?>
-            
-            <td class="type">
-            <?js if (param.type && param.type.names) {?>
-                <?js= self.partial('type.tmpl', param.type.names) ?>
-            <?js } ?>
-            </td>
-            
-            <?js if (params.hasAttributes) {?>
-                <td class="attributes">
-                <?js if (param.optional) { ?>
-                    &lt;optional><br>
-                <?js } ?>
-                    
-                <?js if (param.nullable) { ?>
-                    &lt;nullable><br>
-                <?js } ?>
-                    
-                <?js if (param.variable) { ?>
-                    &lt;repeatable><br>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <?js if (params.hasDefault) {?>
-                <td class="default">
-                <?js if (typeof param.defaultvalue !== 'undefined') { ?>
-                    <?js= self.htmlsafe(param.defaultvalue) ?>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <td class="description last"><?js= param.description ?><?js if (param.subparams) { ?>
-                <h6>Properties</h6>
-                <?js= self.partial('params.tmpl', param.subparams) ?>
-            <?js } ?></td>
-        </tr>
-       
-       <?js }); ?>
-       </tbody>
-</table>
\ No newline at end of file
diff --git a/scripts/templates/xtuple/tmpl/properties.tmpl b/scripts/templates/xtuple/tmpl/properties.tmpl
deleted file mode 100644 (file)
index 97a3d23..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?js
-    var props = obj;
-    
-    /* sort subprops under their parent props (like opts.classname) */
-    var parentProp = null;
-    props.forEach(function(prop, i) {
-        if (!prop) { return; }
-        if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) {
-            prop.name = prop.name.substr(parentProp.name.length+1);
-            parentProp.subprops = parentProp.subprops || [];
-            parentProp.subprops.push(prop);
-            props[i] = null;
-        }
-        else {
-            parentProp = prop;
-        }
-    });
-    
-    /* determine if we need extra columns, "attributes" and "default" */
-    props.hasAttributes = false;
-    props.hasDefault = false;
-    props.hasName = false;
-    
-    props.forEach(function(prop) {
-        if (!prop) { return; }
-        
-        if (prop.optional || prop.nullable) {
-            props.hasAttributes = true;
-        }
-        
-        if (prop.name) {
-            props.hasName = true;
-        }
-        
-        if (typeof prop.defaultvalue !== 'undefined') {
-            props.hasDefault = true;
-        }
-    });
-?>
-
-<table class="props">
-    <thead>
-       <tr>
-               <?js if (props.hasName) {?>
-               <th>Name</th>
-               <?js } ?>
-               
-               <th>Type</th>
-               
-               <?js if (props.hasAttributes) {?>
-               <th>Argument</th>
-               <?js } ?>
-               
-               <?js if (props.hasDefault) {?>
-               <th>Default</th>
-               <?js } ?>
-               
-               <th class="last">Description</th>
-       </tr>
-       </thead>
-       
-       <tbody>
-       <?js
-        var self = this;
-           props.forEach(function(prop) {
-               if (!prop) { return; }
-       ?>
-       
-        <tr>
-            <?js if (props.hasName) {?>
-                <td class="name"><code><?js= prop.name ?></code></td>
-            <?js } ?>
-            
-            <td class="type">
-            <?js if (prop.type && prop.type.names) {?>
-                <?js= self.partial('type.tmpl', prop.type.names) ?>
-            <?js } ?>
-            </td>
-            
-            <?js if (props.hasAttributes) {?>
-                <td class="attributes">
-                <?js if (prop.optional) { ?>
-                    &lt;optional><br>
-                <?js } ?>
-                    
-                <?js if (prop.nullable) { ?>
-                    &lt;nullable><br>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <?js if (props.hasDefault) {?>
-                <td class="default">
-                <?js if (typeof prop.defaultvalue !== 'undefined') { ?>
-                    <?js= self.htmlsafe(prop.defaultvalue) ?>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <td class="description last"><?js= prop.description ?><?js if (prop.subprops) { ?>
-                <h6>Properties</h6><?js= self.partial('properties.tmpl', prop.subprops) ?>
-            <?js } ?></td>
-        </tr>
-       
-       <?js }); ?>
-       </tbody>
-</table>
\ No newline at end of file
diff --git a/scripts/templates/xtuple/tmpl/returns.tmpl b/scripts/templates/xtuple/tmpl/returns.tmpl
deleted file mode 100644 (file)
index 32e059e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?js
-var data = obj;
-if (data.description) {
-?>
-<div class="param-desc">
-    <?js= description ?>
-</div>
-<?js } ?>
-
-<?js if (data.type && data.type.names) {?>
-<dl>
-       <dt>
-               Type
-       </dt>
-       <dd>
-               <?js= this.partial('type.tmpl', data.type.names) ?>
-       </dd>
-</dl>
-<?js } ?>
\ No newline at end of file
diff --git a/scripts/templates/xtuple/tmpl/source.tmpl b/scripts/templates/xtuple/tmpl/source.tmpl
deleted file mode 100644 (file)
index e1092ef..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?js
-    var data = obj;
-?>
-    <section>
-        <article>
-            <pre class="prettyprint source"><code><?js= data.code ?></code></pre>
-        </article>
-    </section>
\ No newline at end of file
diff --git a/scripts/templates/xtuple/tmpl/tutorial.tmpl b/scripts/templates/xtuple/tmpl/tutorial.tmpl
deleted file mode 100644 (file)
index b0c79c1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<section>
-    
-<header>
-    <?js if (children.length > 0) { ?>
-    <ul><?js
-        var self = this;
-        children.forEach(function(t) { ?>
-        <li><?js= self.tutoriallink(t.name) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <h2><?js= header ?></h2>
-</header>  
-
-<article>
-    <?js= content ?>
-</article>
-
-</section>  
diff --git a/scripts/templates/xtuple/tmpl/type.tmpl b/scripts/templates/xtuple/tmpl/type.tmpl
deleted file mode 100644 (file)
index db8194d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?js
-       var data = obj;
-    var self = this;
-    data.forEach(function(name, i) { ?>
-<span class="param-type"><?js= self.linkto(name, self.htmlsafe(name)) ?></span>
-<?js if (i < data.length-1) { ?>|<?js } ?>
-<?js }); ?>
\ No newline at end of file
diff --git a/scripts/templates/xtuple_specs/README.md b/scripts/templates/xtuple_specs/README.md
deleted file mode 100644 (file)
index a7bd96b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-The default template for JSDoc 3 uses: [the Taffy Database library](http://taffydb.com/) and the [Underscore Template library](http://documentcloud.github.com/underscore/#template).
diff --git a/scripts/templates/xtuple_specs/publish.js b/scripts/templates/xtuple_specs/publish.js
deleted file mode 100644 (file)
index d80da8c..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*global env: true */
-var template = require('jsdoc/template'),
-    fs = require('jsdoc/fs'),
-    path = require('jsdoc/path'),
-    taffy = require('taffydb').taffy,
-    handle = require('jsdoc/util/error').handle,
-    helper = require('jsdoc/util/templateHelper'),
-    htmlsafe = helper.htmlsafe,
-    linkto = helper.linkto,
-    resolveAuthorLinks = helper.resolveAuthorLinks,
-    scopeToPunc = helper.scopeToPunc,
-    hasOwnProp = Object.prototype.hasOwnProperty,
-    data,
-    view,
-    outdir = env.opts.destination;
-
-
-function find(spec) {
-    return helper.find(data, spec);
-}
-
-function tutoriallink(tutorial) {
-    return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' });
-}
-
-function getAncestorLinks(doclet) {
-    return helper.getAncestorLinks(data, doclet);
-}
-
-function hashToLink(doclet, hash) {
-    if ( !/^(#.+)/.test(hash) ) { return hash; }
-
-    var url = helper.createLink(doclet);
-
-    url = url.replace(/(#.+|$)/, hash);
-    return '<a href="' + url + '">' + hash + '</a>';
-}
-
-function needsSignature(doclet) {
-    var needsSig = false;
-
-    // function and class definitions always get a signature
-    if (doclet.kind === 'function' || doclet.kind === 'class') {
-        needsSig = true;
-    }
-    // typedefs that contain functions get a signature, too
-    else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names &&
-        doclet.type.names.length) {
-        for (var i = 0, l = doclet.type.names.length; i < l; i++) {
-            if (doclet.type.names[i].toLowerCase() === 'function') {
-                needsSig = true;
-                break;
-            }
-        }
-    }
-
-    return needsSig;
-}
-
-function addSignatureParams(f) {
-    var params = helper.getSignatureParams(f, 'optional');
-
-    f.signature = (f.signature || '') + '('+params.join(', ')+')';
-}
-
-function addSignatureReturns(f) {
-    var returnTypes = helper.getSignatureReturns(f);
-
-    f.signature = '<span class="signature">'+(f.signature || '') + '</span>' + '<span class="type-signature">'+(returnTypes.length? ' &rarr; {'+returnTypes.join('|')+'}' : '')+'</span>';
-}
-
-function addSignatureTypes(f) {
-    var types = helper.getSignatureTypes(f);
-
-    f.signature = (f.signature || '') + '<span class="type-signature">'+(types.length? ' :'+types.join('|') : '')+'</span>';
-}
-
-function addAttribs(f) {
-    var attribs = helper.getAttribs(f);
-
-    f.attribs = '<span class="type-signature">'+htmlsafe(attribs.length? '<'+attribs.join(', ')+'> ' : '')+'</span>';
-}
-
-function shortenPaths(files, commonPrefix) {
-    // always use forward slashes
-    var regexp = new RegExp('\\\\', 'g');
-
-    Object.keys(files).forEach(function (file) {
-        files[file].shortened = files[file].resolved.replace(commonPrefix, '')
-            .replace(regexp, '/');
-    });
-
-    return files;
-}
-
-function resolveSourcePath(filepath) {
-    return path.resolve(process.cwd(), filepath);
-}
-
-function getPathFromDoclet(doclet) {
-    if (!doclet.meta) {
-        return;
-    }
-
-    var filepath = doclet.meta.path && doclet.meta.path !== 'null' ?
-        doclet.meta.path + '/' + doclet.meta.filename :
-        doclet.meta.filename;
-
-    return filepath;
-}
-
-function generate(title, docs, filename, resolveLinks) {
-    resolveLinks = resolveLinks === false ? false : true;
-
-    var docData = {
-        title: title,
-        docs: docs
-    };
-
-    var outpath = path.join(outdir, filename),
-        html = view.render('container.tmpl', docData);
-
-    if (resolveLinks) {
-        html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
-    }
-
-    fs.writeFileSync(outpath, html, 'utf8');
-}
-
-function generateSourceFiles(sourceFiles) {
-    Object.keys(sourceFiles).forEach(function (file) {
-        var source;
-        // links are keyed to the shortened path in each doclet's `meta.filename` property
-        var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened);
-        helper.registerLink(sourceFiles[file].shortened, sourceOutfile);
-
-        try {
-            source = {
-                kind: 'source',
-                code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, 'utf8') )
-            };
-        }
-        catch(e) {
-            handle(e);
-        }
-
-        generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
-            false);
-    });
-}
-
-/**
- * Look for classes or functions with the same name as modules (which indicates that the module
- * exports only that class or function), then attach the classes or functions to the `module`
- * property of the appropriate module doclets. The name of each class or function is also updated
- * for display purposes. This function mutates the original arrays.
- *
- * @private
- * @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
- * check.
- * @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
- */
-function attachModuleSymbols(doclets, modules) {
-    var symbols = {};
-
-    // build a lookup table
-    doclets.forEach(function (symbol) {
-        symbols[symbol.longname] = symbol;
-    });
-
-    return modules.map(function (module) {
-        if (symbols[module.longname]) {
-            module.module = symbols[module.longname];
-            module.module.name = module.module.name.replace('module:', 'require("') + '")';
-        }
-    });
-}
-
-/**
- * Create the navigation sidebar.
- * @param {object} members The members that will be used to create the sidebar.
- * @param {array<object>} members.classes
- * @param {array<object>} members.externals
- * @param {array<object>} members.globals
- * @param {array<object>} members.mixins
- * @param {array<object>} members.modules
- * @param {array<object>} members.namespaces
- * @param {array<object>} members.tutorials
- * @param {array<object>} members.events
- * @return {string} The HTML for the navigation sidebar.
- */
-function buildNav(members) {
-    var nav = '<a href="index.html">Index</a>',
-        seen = {},
-        hasClassList = false,
-        classNav = '',
-        globalNav = '';
-
-    if (members.modules.length) {
-        nav += '<h3>Modules</h3><ul>';
-        members.modules.forEach(function (m) {
-            if ( !hasOwnProp.call(seen, m.longname) ) {
-                nav += '<li>'+linkto(m.longname, m.name)+'</li>';
-            }
-            seen[m.longname] = true;
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.externals.length) {
-        nav += '<h3>Externals</h3><ul>';
-        members.externals.forEach(function (e) {
-            if ( !hasOwnProp.call(seen, e.longname) ) {
-                nav += '<li>'+linkto( e.longname, e.name.replace(/(^"|"$)/g, '') )+'</li>';
-            }
-            seen[e.longname] = true;
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.classes.length) {
-        members.classes.forEach(function (c) {
-            if ( !hasOwnProp.call(seen, c.longname) ) {
-                classNav += '<li>'+linkto(c.longname, c.name)+'</li>';
-            }
-            seen[c.longname] = true;
-        });
-
-        if (classNav !== '') {
-            nav += '<h3>Business Objects</h3><ul>';
-            nav += classNav;
-            nav += '</ul>';
-        }
-    }
-
-    if (members.events.length) {
-        nav += '<h3>Events</h3><ul>';
-        members.events.forEach(function (e) {
-            if ( !hasOwnProp.call(seen, e.longname) ) {
-                nav += '<li>'+linkto(e.longname, e.name)+'</li>';
-            }
-            seen[e.longname] = true;
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.namespaces.length) {
-        nav += '<h3>Namespaces</h3><ul>';
-        members.namespaces.forEach(function (n) {
-            if ( !hasOwnProp.call(seen, n.longname) ) {
-                nav += '<li>'+linkto(n.longname, n.name)+'</li>';
-            }
-            seen[n.longname] = true;
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.mixins.length) {
-        nav += '<h3>Mixins</h3><ul>';
-        members.mixins.forEach(function (m) {
-            if ( !hasOwnProp.call(seen, m.longname) ) {
-                nav += '<li>'+linkto(m.longname, m.name)+'</li>';
-            }
-            seen[m.longname] = true;
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.tutorials.length) {
-        nav += '<h3>Tutorials</h3><ul>';
-        members.tutorials.forEach(function (t) {
-            nav += '<li>'+tutoriallink(t.name)+'</li>';
-        });
-
-        nav += '</ul>';
-    }
-
-    if (members.globals.length) {
-        members.globals.forEach(function (g) {
-            if ( g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname) ) {
-                globalNav += '<li>' + linkto(g.longname, g.name) + '</li>';
-            }
-            seen[g.longname] = true;
-        });
-
-        if (!globalNav) {
-            // turn the heading into a link so you can actually get to the global page
-            nav += '<h3>' + linkto('global', 'Global') + '</h3>';
-        }
-        else {
-            nav += '<h3>Global</h3><ul>' + globalNav + '</ul>';
-        }
-    }
-
-    return nav;
-}
-
-
-/**
-    @param {TAFFY} taffyData See <http://taffydb.com/>.
-    @param {object} opts
-    @param {Tutorial} tutorials
- */
-exports.publish = function (taffyData, opts, tutorials) {
-    data = taffyData;
-
-    var conf = env.conf.templates || {};
-    conf['default'] = conf['default'] || {};
-
-    var templatePath = opts.template;
-    view = new template.Template(templatePath + '/tmpl');
-
-    // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
-    // doesn't try to hand them out later
-    var indexUrl = helper.getUniqueFilename('index');
-    // don't call registerLink() on this one! 'index' is also a valid longname
-
-    var globalUrl = helper.getUniqueFilename('global');
-    helper.registerLink('global', globalUrl);
-
-    // set up templating
-    view.layout = 'layout.tmpl';
-
-    // set up tutorials for helper
-    helper.setTutorials(tutorials);
-
-    data = helper.prune(data);
-    data.sort('longname, version, since');
-    helper.addEventListeners(data);
-
-    var sourceFiles = {};
-    var sourceFilePaths = [];
-    data().each(function (doclet) {
-         doclet.attribs = '';
-
-        if (doclet.examples) {
-            doclet.examples = doclet.examples.map(function (example) {
-                var caption, code;
-
-                if (example.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) {
-                    caption = RegExp.$1;
-                    code    = RegExp.$3;
-                }
-
-                return {
-                    caption: caption || '',
-                    code: code || example
-                };
-            });
-        }
-        if (doclet.see) {
-            doclet.see.forEach(function (seeItem, i) {
-                doclet.see[i] = hashToLink(doclet, seeItem);
-            });
-        }
-
-        // build a list of source files
-        var sourcePath;
-        var resolvedSourcePath;
-        if (doclet.meta) {
-            sourcePath = getPathFromDoclet(doclet);
-            resolvedSourcePath = resolveSourcePath(sourcePath);
-            sourceFiles[sourcePath] = {
-                resolved: resolvedSourcePath,
-                shortened: null
-            };
-            sourceFilePaths.push(resolvedSourcePath);
-        }
-    });
-
-    // update outdir if necessary, then create outdir
-    var packageInfo = ( find({kind: 'package'}) || [] ) [0];
-    if (packageInfo && packageInfo.name) {
-        outdir = path.join(outdir, packageInfo.name, packageInfo.version);
-    }
-    fs.mkPath(outdir);
-
-    // copy the template's static files to outdir
-    var fromDir = path.join(templatePath, 'static');
-    var staticFiles = fs.ls(fromDir, 3);
-
-    staticFiles.forEach(function (fileName) {
-        var toDir = fs.toDir( fileName.replace(fromDir, outdir) );
-        fs.mkPath(toDir);
-        fs.copyFileSync(fileName, toDir);
-    });
-
-    // copy user-specified static files to outdir
-    var staticFilePaths;
-    var staticFileFilter;
-    var staticFileScanner;
-    if (conf['default'].staticFiles) {
-        staticFilePaths = conf['default'].staticFiles.paths || [];
-        staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf['default'].staticFiles);
-        staticFileScanner = new (require('jsdoc/src/scanner')).Scanner();
-
-        staticFilePaths.forEach(function (filePath) {
-            var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter);
-
-            extraStaticFiles.forEach(function (fileName) {
-                var sourcePath = fs.statSync(filePath).isDirectory() ? filePath :
-                    path.dirname(filePath);
-                var toDir = fs.toDir( fileName.replace(sourcePath, outdir) );
-                fs.mkPath(toDir);
-                fs.copyFileSync(fileName, toDir);
-            });
-        });
-    }
-
-    if (sourceFilePaths.length) {
-        sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) );
-    }
-    data().each(function (doclet) {
-        var url = helper.createLink(doclet);
-        helper.registerLink(doclet.longname, url);
-
-        // replace the filename with a shortened version of the full path
-        var docletPath;
-        if (doclet.meta) {
-            docletPath = getPathFromDoclet(doclet);
-            docletPath = sourceFiles[docletPath].shortened;
-            if (docletPath) {
-                doclet.meta.filename = docletPath;
-            }
-        }
-    });
-
-    data().each(function (doclet) {
-        var url = helper.longnameToUrl[doclet.longname];
-
-        if (url.indexOf('#') > -1) {
-            doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop();
-        }
-        else {
-            doclet.id = doclet.name;
-        }
-
-        if ( needsSignature(doclet) ) {
-            addSignatureParams(doclet);
-            addSignatureReturns(doclet);
-            addAttribs(doclet);
-        }
-    });
-
-    // do this after the urls have all been generated
-    data().each(function (doclet) {
-        doclet.ancestors = getAncestorLinks(doclet);
-
-        if (doclet.kind === 'member') {
-            addSignatureTypes(doclet);
-            addAttribs(doclet);
-        }
-
-        if (doclet.kind === 'constant') {
-            addSignatureTypes(doclet);
-            addAttribs(doclet);
-            doclet.kind = 'member';
-        }
-    });
-
-    var members = helper.getMembers(data);
-    members.tutorials = tutorials.children;
-
-    // add template helpers
-    view.find = find;
-    view.linkto = linkto;
-    view.resolveAuthorLinks = resolveAuthorLinks;
-    view.tutoriallink = tutoriallink;
-    view.htmlsafe = htmlsafe;
-
-    // once for all
-    view.nav = buildNav(members);
-    attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }),
-        members.modules );
-
-    // only output pretty-printed source files if requested; do this before generating any other
-    // pages, so the other pages can link to the source files
-    if (conf['default'].outputSourceFiles) {
-        generateSourceFiles(sourceFiles);
-    }
-
-    if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); }
-
-    // index page displays information from package.json and lists files
-    var files = find({kind: 'file'}),
-        packages = find({kind: 'package'});
-
-    generate('Index',
-        packages.concat(
-            [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]
-        ).concat(files),
-    indexUrl);
-
-    // set up the lists that we'll use to generate pages
-    var classes = taffy(members.classes);
-    var modules = taffy(members.modules);
-    var namespaces = taffy(members.namespaces);
-    var mixins = taffy(members.mixins);
-    var externals = taffy(members.externals);
-
-    Object.keys(helper.longnameToUrl).forEach(function (longname) {
-        var myClasses = helper.find(classes, {longname: longname});
-        if (myClasses.length) {
-            generate('Business Object: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]);
-        }
-
-        var myModules = helper.find(modules, {longname: longname});
-        if (myModules.length) {
-            generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]);
-        }
-
-        var myNamespaces = helper.find(namespaces, {longname: longname});
-        if (myNamespaces.length) {
-            generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]);
-        }
-
-        var myMixins = helper.find(mixins, {longname: longname});
-        if (myMixins.length) {
-            generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]);
-        }
-
-        var myExternals = helper.find(externals, {longname: longname});
-        if (myExternals.length) {
-            generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]);
-        }
-    });
-
-    // TODO: move the tutorial functions to templateHelper.js
-    function generateTutorial(title, tutorial, filename) {
-        var tutorialData = {
-            title: title,
-            header: tutorial.title,
-            content: tutorial.parse(),
-            children: tutorial.children
-        };
-
-        var tutorialPath = path.join(outdir, filename),
-            html = view.render('tutorial.tmpl', tutorialData);
-
-        // yes, you can use {@link} in tutorials too!
-        html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
-
-        fs.writeFileSync(tutorialPath, html, 'utf8');
-    }
-
-    // tutorials can have only one parent so there is no risk for loops
-    function saveChildren(node) {
-        node.children.forEach(function (child) {
-            generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name));
-            saveChildren(child);
-        });
-    }
-    saveChildren(tutorials);
-};
diff --git a/scripts/templates/xtuple_specs/static/scripts/linenumber.js b/scripts/templates/xtuple_specs/static/scripts/linenumber.js
deleted file mode 100644 (file)
index a0c570d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-(function() {
-    var counter = 0;
-    var numbered;
-    var source = document.getElementsByClassName('prettyprint source');
-
-    if (source && source[0]) {
-        source = source[0].getElementsByTagName('code')[0];
-
-        numbered = source.innerHTML.split('\n');
-        numbered = numbered.map(function(item) {
-            counter++;
-            return '<span id="line' + counter + '"></span>' + item;
-        });
-
-        source.innerHTML = numbered.join('\n');
-    }
-})();
diff --git a/scripts/templates/xtuple_specs/static/scripts/prettify/Apache-License-2.0.txt b/scripts/templates/xtuple_specs/static/scripts/prettify/Apache-License-2.0.txt
deleted file mode 100644 (file)
index d645695..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/scripts/templates/xtuple_specs/static/scripts/prettify/lang-css.js b/scripts/templates/xtuple_specs/static/scripts/prettify/lang-css.js
deleted file mode 100644 (file)
index 041e1f5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n\f"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
-/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
diff --git a/scripts/templates/xtuple_specs/static/scripts/prettify/prettify.js b/scripts/templates/xtuple_specs/static/scripts/prettify/prettify.js
deleted file mode 100644 (file)
index eef5ad7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
-(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
-[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
-f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
-(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
-{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
-t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
-"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
-l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
-q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
-q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
-"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
-a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
-for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
-m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
-a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
-j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
-"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
-H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
-J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
-I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
-["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
-/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
-["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
-hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
-!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
-250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
-PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
diff --git a/scripts/templates/xtuple_specs/static/styles/jsdoc-default.css b/scripts/templates/xtuple_specs/static/styles/jsdoc-default.css
deleted file mode 100644 (file)
index ea49f60..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-html
-{
-    overflow: auto;
-    background-color: #fff;
-}
-
-body
-{
-       font: 14px "DejaVu Sans Condensed", "Liberation Sans", "Nimbus Sans L", Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans serif;
-       line-height: 130%;
-       color: #000;
-       background-color: #fff;
-}
-
-a {
-    color: #444;
-}
-
-a:visited {
-    color: #444;
-}
-
-a:active {
-    color: #444;
-}
-
-header
-{
-       display: block;
-       padding: 6px 4px;
-}
-
-.class-description {
-    font-style: italic;
-       font-family: Palatino, 'Palatino Linotype', serif;
-       font-size: 130%;
-       line-height: 140%;
-       margin-bottom: 1em;
-       margin-top: 1em;
-}
-
-#main {
-    float: left;
-    width: 100%;
-}
-
-section
-{
-       display: block;
-       
-       background-color: #fff;
-       padding: 12px 24px;
-    border-bottom: 1px solid #ccc;
-    margin-right: 240px;
-}
-
-.variation {
-    display: none;
-}
-
-.optional:after {
-       content: "opt";
-       font-size: 60%;
-       color: #aaa;
-       font-style: italic;
-       font-weight: lighter;
-}
-
-nav
-{
-       display: block;
-       float: left;
-    margin-left: -230px;
-    margin-top: 28px;
-    width: 220px;
-    border-left: 1px solid #ccc;
-    padding-left: 9px;
-}
-
-nav ul {
-    font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif;
-    font-size: 100%;
-    line-height: 17px;
-    padding:0;
-    margin:0;
-    list-style-type:none;
-}
-
-nav h2 a, nav h2 a:visited {
-    color: #A35A00;
-    text-decoration: none;
-}
-
-nav h3 {
-    margin-top: 12px;
-}
-
-nav li {
-    margin-top: 6px;
-}
-
-nav a {
-    color: #5C5954;
-}
-
-nav a:visited {
-    color: #5C5954;
-}
-
-nav a:active {
-    color: #5C5954;
-}
-
-footer {
-    display: block;
-    padding: 6px;
-    margin-top: 12px;
-    font-style: italic;
-    font-size: 90%;
-}
-
-h1
-{
-       font-size: 200%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 6px 0 9px 0;
-}
-
-h2
-{
-       font-size: 170%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 6px 0 3px 0;
-}
-
-h3
-{
-       font-size: 150%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin-top: 16px;
-       margin: 6px 0 3px 0;
-}
-
-h4
-{
-       font-size: 130%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin-top: 16px;
-       margin: 18px 0 3px 0;
-       color: #A35A00;
-}
-
-h5, .container-overview .subsection-title
-{
-       font-size: 120%;
-       font-weight: bold;
-       letter-spacing: -0.01em;
-       margin: 8px 0 3px -16px;
-}
-
-h6
-{
-       font-size: 100%;
-       letter-spacing: -0.01em;
-       margin: 6px 0 3px 0;
-       font-style: italic;
-}
-
-.ancestors { color: #999; }
-.ancestors a
-{
-    color: #999 !important;
-    text-decoration: none;
-}
-
-.important
-{
-       font-weight: bold;
-       color: #950B02;
-}
-
-.yes-def {
-    text-indent: -1000px;
-}
-
-.type-signature {
-    color: #aaa;
-}
-
-.name, .signature {
-       font-family: Consolas, "Lucida Console", Monaco, monospace;
-}
-
-.details { margin-top: 14px; }
-.details dt { width:100px; float:left; border-left: 2px solid #DDD; padding-left: 10px;  padding-top: 6px; }
-.details dd { margin-left: 50px; }
-.details ul { margin: 0; }
-.details ul { list-style-type: none; }
-.details li { margin-left: 30px; padding-top: 6px; }
-
-.description {
-       margin-bottom: 1em;
-       margin-left: -16px;
-       margin-top: 1em;
-}
-
-.code-caption
-{
-       font-style: italic;
-       font-family: Palatino, 'Palatino Linotype', serif;
-       font-size: 107%;
-       margin: 0;
-}
-
-.prettyprint
-{
-       border: 1px solid #ddd;
-       width: 80%;
-    overflow: auto;
-}
-
-.prettyprint.source {
-    width: inherit;
-}
-
-.prettyprint code
-{
-       font-family: Consolas, 'Lucida Console', Monaco, monospace;
-       font-size: 100%;
-       line-height: 18px;
-       display: block;
-       padding: 4px 12px;
-       margin: 0;
-       background-color: #fff;
-       color: #000;
-       border-left: 3px #ddd solid;
-}
-
-.params, .props
-{
-       border-spacing: 0;
-       border: 0;
-       border-collapse: collapse;
-}
-
-.params .name, .props .name, .name code {
-       color: #A35A00;
-       font-family: Consolas, 'Lucida Console', Monaco, monospace;
-       font-size: 100%;
-}
-
-.params td, .params th, .props td, .props th
-{
-       border: 1px solid #ddd;
-       margin: 0px;
-       text-align: left;
-       vertical-align: top;
-       padding: 4px 6px;
-       display: table-cell;
-}
-
-.params thead tr, .props thead tr
-{
-       background-color: #ddd;
-       font-weight: bold;
-}
-
-.params .params thead tr, .props .props thead tr
-{
-       background-color: #fff;
-       font-weight: bold;
-}
-
-.params th, .props th { border-right: 1px solid #aaa; }
-.params thead .last, .props thead .last { border-right: 1px solid #ddd; }
-
-.disabled {
-    color: #454545;
-}
diff --git a/scripts/templates/xtuple_specs/static/styles/prettify-jsdoc.css b/scripts/templates/xtuple_specs/static/styles/prettify-jsdoc.css
deleted file mode 100644 (file)
index 5a2526e..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* JSDoc prettify.js theme */
-
-/* plain text */
-.pln {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* string content */
-.str {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a keyword */
-.kwd {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a comment */
-.com {
-  font-weight: normal;
-  font-style: italic;
-}
-
-/* a type name */
-.typ {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a literal value */
-.lit {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* punctuation */
-.pun {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* lisp open bracket */
-.opn {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* lisp close bracket */
-.clo {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a markup tag name */
-.tag {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a markup attribute name */
-.atn {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a markup attribute value */
-.atv {
-  color: #006400;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a declaration */
-.dec {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* a variable name */
-.var {
-  color: #000000;
-  font-weight: normal;
-  font-style: normal;
-}
-
-/* a function name */
-.fun {
-  color: #000000;
-  font-weight: bold;
-  font-style: normal;
-}
-
-/* Specify class=linenums on a pre to get line numbering */
-ol.linenums {
-  margin-top: 0;
-  margin-bottom: 0;
-}
diff --git a/scripts/templates/xtuple_specs/static/styles/prettify-tomorrow.css b/scripts/templates/xtuple_specs/static/styles/prettify-tomorrow.css
deleted file mode 100644 (file)
index aa2908c..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Tomorrow Theme */
-/* Original theme - https://github.com/chriskempson/tomorrow-theme */
-/* Pretty printing styles. Used with prettify.js. */
-/* SPAN elements with the classes below are added by prettyprint. */
-/* plain text */
-.pln {
-  color: #4d4d4c; }
-
-@media screen {
-  /* string content */
-  .str {
-    color: #718c00; }
-
-  /* a keyword */
-  .kwd {
-    color: #8959a8; }
-
-  /* a comment */
-  .com {
-    color: #8e908c; }
-
-  /* a type name */
-  .typ {
-    color: #4271ae; }
-
-  /* a literal value */
-  .lit {
-    color: #f5871f; }
-
-  /* punctuation */
-  .pun {
-    color: #4d4d4c; }
-
-  /* lisp open bracket */
-  .opn {
-    color: #4d4d4c; }
-
-  /* lisp close bracket */
-  .clo {
-    color: #4d4d4c; }
-
-  /* a markup tag name */
-  .tag {
-    color: #c82829; }
-
-  /* a markup attribute name */
-  .atn {
-    color: #f5871f; }
-
-  /* a markup attribute value */
-  .atv {
-    color: #3e999f; }
-
-  /* a declaration */
-  .dec {
-    color: #f5871f; }
-
-  /* a variable name */
-  .var {
-    color: #c82829; }
-
-  /* a function name */
-  .fun {
-    color: #4271ae; } }
-/* Use higher contrast and text-weight for printable form. */
-@media print, projection {
-  .str {
-    color: #060; }
-
-  .kwd {
-    color: #006;
-    font-weight: bold; }
-
-  .com {
-    color: #600;
-    font-style: italic; }
-
-  .typ {
-    color: #404;
-    font-weight: bold; }
-
-  .lit {
-    color: #044; }
-
-  .pun, .opn, .clo {
-    color: #440; }
-
-  .tag {
-    color: #006;
-    font-weight: bold; }
-
-  .atn {
-    color: #404; }
-
-  .atv {
-    color: #060; } }
-/* Style */
-/*
-pre.prettyprint {
-  background: white;
-  font-family: Menlo, Monaco, Consolas, monospace;
-  font-size: 12px;
-  line-height: 1.5;
-  border: 1px solid #ccc;
-  padding: 10px; }
-*/
-
-/* Specify class=linenums on a pre to get line numbering */
-ol.linenums {
-  margin-top: 0;
-  margin-bottom: 0; }
-
-/* IE indents via margin-left */
-li.L0,
-li.L1,
-li.L2,
-li.L3,
-li.L4,
-li.L5,
-li.L6,
-li.L7,
-li.L8,
-li.L9 {
-  /* */ }
-
-/* Alternate shading for lines */
-li.L1,
-li.L3,
-li.L5,
-li.L7,
-li.L9 {
-  /* */ }
diff --git a/scripts/templates/xtuple_specs/tmpl/container.tmpl b/scripts/templates/xtuple_specs/tmpl/container.tmpl
deleted file mode 100644 (file)
index dbc5493..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<?js
-    var self = this;
-    var subgroupOrder = [
-      "Setup", 
-      "Privileges", 
-      "Settings", 
-      "Buttons", 
-      "Navigation", 
-      "Other"
-    ];
-    docs.forEach(function(doc, i) {
-?>
-
-<?js if (doc.kind === 'mainpage' || (doc.kind === 'package')) { ?>
-    <?js= self.partial('mainpage.tmpl', doc) ?>
-<?js } else if (doc.kind === 'source') { ?>
-    <?js= self.partial('source.tmpl', doc) ?>
-<?js } else { ?>
-
-<section>
-    
-<header>
-    <h2><?js if (doc.ancestors && doc.ancestors.length) { ?>
-        <span class="ancestors"><?js= doc.ancestors.join('') ?></span>
-    <?js } ?>
-    Definition
-    <?js if (doc.variation) { ?>
-        <sup class="variation"><?js= doc.variation ?></sup>
-    <?js } ?></h2>
-    <?js if (doc.classdesc) { ?>
-        <div class="class-description"><?js= doc.classdesc ?></div>
-    <?js } ?>
-</header>  
-
-<article>
-    <div class="container-overview">
-    <?js if (doc.kind === 'module' && doc.module) { ?>
-        <?js= self.partial('method.tmpl', doc.module) ?>
-    <?js } ?>
-    
-    <?js if (doc.kind === 'class') { ?>
-        <?js= self.partial('method.tmpl', doc) ?>
-    <?js } else { ?>
-        <?js if (doc.description) { ?>
-            <div class="description"><?js= doc.description ?></div>
-        <?js } ?>
-        
-        <?js= self.partial('details.tmpl', doc) ?>
-        
-        <?js if (doc.examples && doc.examples.length) { ?>
-            <h3>Example<?js= doc.examples.length > 1? 's':'' ?></h3>
-            <?js= self.partial('examples.tmpl', doc.examples) ?>
-        <?js } ?>
-    <?js } ?>
-    </div>
-    
-    <?js if (doc.augments && doc.augments.length) { ?>
-        <h3 class="subsection-title">Extends</h3>
-        
-        <ul><?js doc.augments.forEach(function(a) { ?>
-            <li><?js= self.linkto(a, a) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (doc.mixes && doc.mixes.length) { ?>
-        <h3 class="subsection-title">Mixes In</h3>
-        
-        <ul><?js doc.mixes.forEach(function(a) { ?>
-            <li><?js= self.linkto(a, a) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (doc.requires && doc.requires.length) { ?>
-        <h3 class="subsection-title">Requires</h3>
-        
-        <ul><?js doc.requires.forEach(function(r) { ?>
-            <li><?js= self.linkto(r, r) ?></li>
-        <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js
-        var namespaces = self.find({kind: 'namespace', memberof: doc.longname}); 
-        if (doc.kind !== 'globalobj' && namespaces && namespaces.length) { 
-    ?>
-        <h3 class="subsection-title">Namesplaces</h3>
-        
-        <dl><?js namespaces.forEach(function(n) { ?>
-            <dt><a href="namespaces.html#<?js= n.longname ?>"><?js= self.linkto(n.longname, n.name) ?></a></dt>
-            <dd><?js if (n.summary) { ?><?js= n.summary ?><?js } ?></dd>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var classes = self.find({kind: 'class', memberof: doc.longname}); 
-        if (doc.kind !== 'globalobj' && classes && classes.length) { 
-    ?>
-        <h3 class="subsection-title">Classes</h3>
-        
-        <dl><?js classes.forEach(function(c) { ?>
-            <dt><?js= self.linkto(c.longname, c.longname) ?></dt>
-            <dd><?js if (c.summary) { ?><?js= c.summary ?><?js } ?></dd>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var members = self.find({kind: 'member', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
-        if (members && members.length && members.forEach) { 
-          global.headersSeen = [];
-          members.map(function (member) {
-            if(member.name === '-') {
-              member.name = 'Other';
-            }
-          });
-          members.sort(function (a, b) {
-            var subgroupA = subgroupOrder.indexOf(a.name),
-              subgroupB = subgroupOrder.indexOf(b.name);
-
-            if(subgroupA < 0) {
-              subgroupA = 9999;
-            }
-            if(subgroupB < 0) {
-              subgroupB = 9999;
-            }
-            return subgroupA - subgroupB;
-          });
-    ?>
-        <h2 class="subsection-title">Related Information</h2>
-        
-        <dl><?js members.forEach(function(p) { ?>
-            <ul><?js= self.partial('members.tmpl', p) ?></ul>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var methods = self.find({kind: 'function', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
-        if (methods && methods.length && methods.forEach) { 
-    ?>
-        <h3 class="subsection-title">Methods</h3>
-        
-        <dl><?js methods.forEach(function(m) { ?>
-            <?js= self.partial('method.tmpl', m) ?>
-        <?js }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var typedefs = self.find({kind: 'typedef', memberof: title === 'Global' ? {isUndefined: true} : doc.longname}); 
-        if (typedefs && typedefs.length && typedefs.forEach) { 
-    ?>
-        <h3 class="subsection-title">Type Definitions</h3>
-        
-        <dl><?js typedefs.forEach(function(e) {
-                if (e.signature) {
-            ?>
-                <?js= self.partial('method.tmpl', e) ?>
-            <?js
-                }
-                else {
-            ?>
-                <?js= self.partial('members.tmpl', e) ?>
-            <?js
-                }
-            }); ?></dl>
-    <?js } ?>
-    
-    <?js
-        var events = self.find({kind: 'event', memberof: title === 'Global' ? {isUndefined: true} : doc.longname}); 
-        if (events && events.length && events.forEach) { 
-    ?>
-        <h3 class="subsection-title">Events</h3>
-        
-        <dl><?js events.forEach(function(e) { ?>
-            <?js= self.partial('method.tmpl', e) ?>
-        <?js }); ?></dl>
-    <?js } ?>
-</article>
-
-</section>  
-<?js } ?>
-
-<?js }); ?>
diff --git a/scripts/templates/xtuple_specs/tmpl/details.tmpl b/scripts/templates/xtuple_specs/tmpl/details.tmpl
deleted file mode 100644 (file)
index 43eeb4c..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dl class="details">
-    <?js
-        var properties = data.properties;
-        if (properties && properties.length && properties.forEach) { 
-    ?>
-        
-        <h3>Properties:</h3>
-        
-        <dl><?js= this.partial('properties.tmpl', properties) ?></dl>
-        
-    <?js } ?>
-        
-    <?js if (data.version) {?>
-    <dt class="tag-version">Version:</dt>
-    <dd class="tag-version"><ul class="dummy"><li><?js= version ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.since) {?>
-    <dt class="tag-since">Since:</dt>
-    <dd class="tag-since"><ul class="dummy"><li><?js= since ?></dd>
-    <?js } ?>
-
-    <?js if (data.inherited && data.inherits) { ?>
-    <dt class="inherited-from">Inherited From:</dt>
-    <dd class="inherited-from"><ul class="dummy"><li>
-        <?js= this.linkto(data.inherits, this.htmlsafe(data.inherits)) ?>
-    </li></dd>
-    <?js } ?>
-    
-    <?js if (data.deprecated) { ?>
-        <dt class="important tag-deprecated">Deprecated:</dt><?js
-            if (data.deprecated === true) { ?><dd class="yes-def tag-deprecated"><ul class="dummy"><li>Yes</li></ul></dd><?js }
-            else { ?><dd><ul class="dummy"><li><?js= data.deprecated ?></li><ul></dd><?js }
-        ?>
-    <?js } ?>
-    
-    <?js if (data.author && author.length) {?>
-    <dt class="tag-author">Author:</dt>
-    <dd class="tag-author">
-        <ul><?js author.forEach(function(a) { ?>
-            <li><?js= self.resolveAuthorLinks(a) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.copyright) {?>
-    <dt class="tag-copyright">Copyright:</dt>
-    <dd class="tag-copyright"><ul class="dummy"><li><?js= copyright ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.license) {?>
-    <dt class="tag-license">License:</dt>
-    <dd class="tag-license"><ul class="dummy"><li><?js= license ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.defaultvalue) {?>
-    <dt class="tag-default">Default Value:</dt>
-    <dd class="tag-default"><ul class="dummy"><li><?js= data.defaultvalue ?></li></ul></dd>
-    <?js } ?>
-    
-    <?js if (data.tutorials && tutorials.length) {?>
-    <dt class="tag-tutorial">Tutorials:</dt>
-    <dd class="tag-tutorial">
-        <ul><?js tutorials.forEach(function(t) { ?>
-            <li><?js= self.tutoriallink(t) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.see && see.length) {?>
-    <dt class="tag-see">See:</dt>
-    <dd class="tag-see">
-        <ul><?js see.forEach(function(s) { ?>
-            <li><?js= self.linkto(s) ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-    
-    <?js if (data.todo && todo.length) {?>
-    <dt class="tag-todo">To Do:</dt>
-    <dd class="tag-todo">
-        <ul><?js todo.forEach(function(t) { ?>
-            <li><?js= t ?></li>
-        <?js }); ?></ul>
-    </dd>
-    <?js } ?>
-</dl>
diff --git a/scripts/templates/xtuple_specs/tmpl/example.tmpl b/scripts/templates/xtuple_specs/tmpl/example.tmpl
deleted file mode 100644 (file)
index e87caa5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<?js var data = obj; ?>
-<pre><code><?js= data ?></code></pre>
diff --git a/scripts/templates/xtuple_specs/tmpl/examples.tmpl b/scripts/templates/xtuple_specs/tmpl/examples.tmpl
deleted file mode 100644 (file)
index 23384c9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?js
-       var data = obj;
-    data.forEach(function(example) {
-        if (example.caption) {
-    ?>
-        <p class="code-caption"><?js= example.caption ?></p>
-    <?js } ?>
-    <pre class="prettyprint"><code><?js= example.code ?></code></pre>
-<?js
-    });
-?>
\ No newline at end of file
diff --git a/scripts/templates/xtuple_specs/tmpl/exceptions.tmpl b/scripts/templates/xtuple_specs/tmpl/exceptions.tmpl
deleted file mode 100644 (file)
index 78c4e25..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?js
-    var data = obj;
-?>
-<?js if (data.description && data.type && data.type.names) { ?>
-<dl>
-    <dt>
-        <div class="param-desc">
-        <?js= data.description ?>
-        </div>
-    </dt>
-    <dt>
-        <dl>
-            <dt>
-                Type
-            </dt>
-            <dd>
-                <?js= this.partial('type.tmpl', data.type.names) ?>
-            </dd>
-        </dl>
-    </dt>
-</dl>
-<?js } else { ?>
-    <div class="param-desc">
-    <?js if (data.description) { ?>
-        <?js= data.description ?>
-    <?js } else if (data.type && data.type.names) { ?>
-        <?js= this.partial('type.tmpl', data.type.names) ?>
-    <?js } ?>
-    </div>
-<?js } ?>
diff --git a/scripts/templates/xtuple_specs/tmpl/layout.tmpl b/scripts/templates/xtuple_specs/tmpl/layout.tmpl
deleted file mode 100644 (file)
index 827b5ac..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <title>JSDoc: <?js= title ?></title>
-    
-    <script src="scripts/prettify/prettify.js"> </script>
-    <script src="scripts/prettify/lang-css.js"> </script>
-    <!--[if lt IE 9]>
-      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
-    <![endif]-->
-    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
-    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
-</head>
-
-<body>
-
-<div id="main">
-    
-    <h1 class="page-title"><?js= title ?></h1>
-    
-    <?js= content ?>
-</div>
-
-<nav>
-    <?js= this.nav ?>
-</nav>
-
-<br clear="both">
-
-<footer>
-    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc <?js= env.version.number ?></a> on <?js= (new Date()) ?>
-</footer>
-
-<script> prettyPrint(); </script>
-<script src="scripts/linenumber.js"> </script>
-</body>
-</html>
diff --git a/scripts/templates/xtuple_specs/tmpl/mainpage.tmpl b/scripts/templates/xtuple_specs/tmpl/mainpage.tmpl
deleted file mode 100644 (file)
index 64e9e59..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-
-<?js if (data.kind === 'package') { ?>
-    <h3><?js= data.name ?> <?js= data.version ?></h3>
-<?js } ?>
-
-<?js if (data.readme) { ?>
-    <section>
-        <article><?js= data.readme ?></article>
-    </section>
-<?js } ?>
diff --git a/scripts/templates/xtuple_specs/tmpl/members.tmpl b/scripts/templates/xtuple_specs/tmpl/members.tmpl
deleted file mode 100644 (file)
index edd643d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dt>
-    <?js
-      var suppressHeader = false;
-      if(global.headersSeen.indexOf(name) >= 0) {
-        suppressHeader = true;
-      } else {
-        global.headersSeen.push(name);  
-      }
-    ?>
-    <?js if (!suppressHeader) { ?>
-      <h4 class="name" id="<?js= id ?>"><?js= name + (data.signature ? data.signature : '') ?></h4>
-    <?js } ?>
-    
-    <?js if (data.summary) { ?>
-    <p class="summary"><?js= summary ?></p>
-    <?js } ?>
-</dt>
-<dd>
-    <?js if (data.description) { ?>
-      <li><?js= data.description ?>
-    <?js } ?>
-    
-    <?js if (data.type && data.type.names) {?>
-        <h5>Type:</h5>
-        <ul>
-            <li>
-                <?js= self.partial('type.tmpl', data.type.names) ?>
-            </li>
-        </ul>
-    <?js } ?>
-
-    <?js= this.partial('details.tmpl', data) ?>
-    
-    <?js if (data.examples && examples.length) { ?>
-        <h5>Example<?js= examples.length > 1? 's':'' ?></h5>
-        <?js= this.partial('examples.tmpl', examples) ?>
-    <?js } ?>
-</dd>
diff --git a/scripts/templates/xtuple_specs/tmpl/method.tmpl b/scripts/templates/xtuple_specs/tmpl/method.tmpl
deleted file mode 100644 (file)
index 75d12fa..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-<?js
-var data = obj;
-var self = this;
-?>
-<dt>
-    <?js if (kind !== 'class') { ?>
-    <h4 class="name" id="<?js= id ?>"><?js= data.attribs + (kind === 'class' ? 'new ' : '') + name + (kind !== 'event' ? data.signature : '') ?></h4>
-    <?js } ?>
-    
-    <?js if (data.summary) { ?>
-    <p class="summary"><?js= summary ?></p>
-    <?js } ?>
-</dt>
-<dd>
-    
-    <?js if (data.description) { ?>
-    <div class="description">
-        <?js= data.description ?>
-    </div>
-    <?js } ?>
-
-    <?js if (kind === 'event' && data.type && data.type.names) {?>
-        <h5>Type:</h5>
-        <ul>
-            <li>
-                <?js= self.partial('type.tmpl', data.type.names) ?>
-            </li>
-        </ul>
-    <?js } ?>
-    
-    <?js if (data['this']) { ?>
-        <h5>This:</h5>
-        <ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
-    <?js } ?>
-    
-    <?js if (data.params && params.length) { ?>
-        <h5>Parameters:</h5>
-        <?js= this.partial('params.tmpl', params) ?>
-    <?js } ?>
-    
-    <?js= this.partial('details.tmpl', data) ?>
-    
-    <?js if (data.fires && fires.length) { ?>
-    <h5>Fires:</h5>
-    <ul><?js fires.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <?js if (data.listens && listens.length) { ?>
-    <h5>Listens to Events:</h5>
-    <ul><?js listens.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <?js if (data.listeners && listeners.length) { ?>
-    <h5>Listeners of This Event:</h5>
-    <ul><?js listeners.forEach(function(f) { ?>
-        <li><?js= self.linkto(f) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-    
-    <?js if (data.exceptions && exceptions.length) { ?>
-    <h5>Throws:</h5>
-    <?js if (exceptions.length > 1) { ?><ul><?js
-        exceptions.forEach(function(r) { ?>
-            <li><?js= self.partial('exceptions.tmpl', r) ?></li>
-        <?js });
-    ?></ul><?js } else {
-        exceptions.forEach(function(r) { ?>
-            <?js= self.partial('exceptions.tmpl', r) ?>
-        <?js });
-    } } ?>
-    
-    <?js if (data.returns && returns.length) { ?>
-    <h5>Returns:</h5>
-    <?js if (returns.length > 1) { ?><ul><?js
-        returns.forEach(function(r) { ?>
-            <li><?js= self.partial('returns.tmpl', r) ?></li>
-        <?js });
-    ?></ul><?js } else {
-        returns.forEach(function(r) { ?>
-            <?js= self.partial('returns.tmpl', r) ?>
-        <?js });
-    } } ?>
-    
-    <?js if (data.examples && examples.length) { ?>
-        <h5>Example<?js= examples.length > 1? 's':'' ?></h5>
-        <?js= this.partial('examples.tmpl', examples) ?>
-    <?js } ?>
-</dd>
diff --git a/scripts/templates/xtuple_specs/tmpl/params.tmpl b/scripts/templates/xtuple_specs/tmpl/params.tmpl
deleted file mode 100644 (file)
index 7b95114..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<?js
-    var params = obj;
-    
-    /* sort subparams under their parent params (like opts.classname) */
-    var parentParam = null;
-    params.forEach(function(param, i) {
-        if (!param) { return; }
-        if ( parentParam && param.name && param.name.indexOf(parentParam.name + '.') === 0 ) {
-            param.name = param.name.substr(parentParam.name.length+1);
-            parentParam.subparams = parentParam.subparams || [];
-            parentParam.subparams.push(param);
-            params[i] = null;
-        }
-        else {
-            parentParam = param;
-        }
-    });
-    
-    /* determine if we need extra columns, "attributes" and "default" */
-    params.hasAttributes = false;
-    params.hasDefault = false;
-    params.hasName = false;
-    
-    params.forEach(function(param) {
-        if (!param) { return; }
-        
-        if (param.optional || param.nullable || param.variable) {
-            params.hasAttributes = true;
-        }
-        
-        if (param.name) {
-            params.hasName = true;
-        }
-        
-        if (typeof param.defaultvalue !== 'undefined') {
-            params.hasDefault = true;
-        }
-    });
-?>
-
-<table class="params">
-    <thead>
-       <tr>
-               <?js if (params.hasName) {?>
-               <th>Name</th>
-               <?js } ?>
-               
-               <th>Type</th>
-               
-               <?js if (params.hasAttributes) {?>
-               <th>Argument</th>
-               <?js } ?>
-               
-               <?js if (params.hasDefault) {?>
-               <th>Default</th>
-               <?js } ?>
-               
-               <th class="last">Description</th>
-       </tr>
-       </thead>
-       
-       <tbody>
-       <?js
-        var self = this;
-           params.forEach(function(param) {
-               if (!param) { return; }
-       ?>
-       
-        <tr>
-            <?js if (params.hasName) {?>
-                <td class="name"><code><?js= param.name ?></code></td>
-            <?js } ?>
-            
-            <td class="type">
-            <?js if (param.type && param.type.names) {?>
-                <?js= self.partial('type.tmpl', param.type.names) ?>
-            <?js } ?>
-            </td>
-            
-            <?js if (params.hasAttributes) {?>
-                <td class="attributes">
-                <?js if (param.optional) { ?>
-                    &lt;optional><br>
-                <?js } ?>
-                    
-                <?js if (param.nullable) { ?>
-                    &lt;nullable><br>
-                <?js } ?>
-                    
-                <?js if (param.variable) { ?>
-                    &lt;repeatable><br>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <?js if (params.hasDefault) {?>
-                <td class="default">
-                <?js if (typeof param.defaultvalue !== 'undefined') { ?>
-                    <?js= self.htmlsafe(param.defaultvalue) ?>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <td class="description last"><?js= param.description ?><?js if (param.subparams) { ?>
-                <h6>Properties</h6>
-                <?js= self.partial('params.tmpl', param.subparams) ?>
-            <?js } ?></td>
-        </tr>
-       
-       <?js }); ?>
-       </tbody>
-</table>
\ No newline at end of file
diff --git a/scripts/templates/xtuple_specs/tmpl/properties.tmpl b/scripts/templates/xtuple_specs/tmpl/properties.tmpl
deleted file mode 100644 (file)
index 1fa4073..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<?js
-    var props = obj;
-    var endUser = env.conf.templates.endUser;
-    
-    /* sort subprops under their parent props (like opts.classname) */
-    var parentProp = null;
-    props.forEach(function(prop, i) {
-        if (!prop) { return; }
-        if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) {
-            prop.name = prop.name.substr(parentProp.name.length+1);
-            parentProp.subprops = parentProp.subprops || [];
-            parentProp.subprops.push(prop);
-            props[i] = null;
-        }
-        else {
-            parentProp = prop;
-        }
-    });
-    
-    /* determine if we need extra columns, "attributes" and "default" */
-    props.hasAttributes = false;
-    props.hasDefault = false;
-    props.hasName = false;
-    
-    props.forEach(function(prop) {
-        if (!prop) { return; }
-        
-        if (prop.optional || prop.nullable) {
-            props.hasAttributes = true;
-        }
-        
-        if (prop.name) {
-            props.hasName = true;
-        }
-        
-        if (typeof prop.defaultvalue !== 'undefined') {
-            props.hasDefault = true;
-        }
-    });
-?>
-
-<table class="props">
-    <thead>
-       <tr>
-               <?js if (props.hasName) {?>
-               <th>Name</th>
-               <?js } ?>
-               
-               <?js if (!endUser) {?>
-               <th>Type</th>
-               <?js } ?>
-               
-               <?js if (props.hasAttributes) {?>
-               <th>Argument</th>
-               <?js } ?>
-               
-               <?js if (props.hasDefault) {?>
-               <th>Default</th>
-               <?js } ?>
-               
-               <th class="last">Reference</th>
-       </tr>
-       </thead>
-       
-       <tbody>
-       <?js
-        var self = this;
-           props.forEach(function(prop) {
-               if (!prop) { return; }
-            if (!prop.description) {
-              // don't futz with a falsy description
-            } else if(endUser && prop.description.indexOf("()") >= 0) {
-              // () means: don't display this prop at all to the end user
-              return;
-            } else if(endUser) {
-              // don't show square-bracketed text to end users.
-              prop.description = prop.description.replace(/\[.*?\]/, "");
-              prop.description = prop.description.replace("(", "").replace(")", "");
-            } else {
-              prop.description = prop.description.replace(/\(.*?\)/, "");
-              prop.description = prop.description.replace("[", "").replace("]", "");
-            }
-       ?>
-       
-        <tr>
-            <?js if (props.hasName) {?>
-                <td class="name"><code><?js= prop.name ?></code></td>
-            <?js } ?>
-            
-            <?js if (!endUser) {?>
-                <td class="type">
-                <?js if (prop.type && prop.type.names) {?>
-                    <?js= self.partial('type.tmpl', prop.type.names) ?>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <?js if (props.hasAttributes) {?>
-                <td class="attributes">
-                <?js if (prop.optional) { ?>
-                    &lt;optional><br>
-                <?js } ?>
-                    
-                <?js if (prop.nullable) { ?>
-                    &lt;nullable><br>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <?js if (props.hasDefault) {?>
-                <td class="default">
-                <?js if (typeof prop.defaultvalue !== 'undefined') { ?>
-                    <?js= self.htmlsafe(prop.defaultvalue) ?>
-                <?js } ?>
-                </td>
-            <?js } ?>
-            
-            <td class="description last"><?js= prop.description ?><?js if (prop.subprops) { ?>
-                <h6>Properties</h6><?js= self.partial('properties.tmpl', prop.subprops) ?>
-            <?js } ?></td>
-        </tr>
-       
-       <?js }); ?>
-       </tbody>
-</table>
diff --git a/scripts/templates/xtuple_specs/tmpl/returns.tmpl b/scripts/templates/xtuple_specs/tmpl/returns.tmpl
deleted file mode 100644 (file)
index 32e059e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?js
-var data = obj;
-if (data.description) {
-?>
-<div class="param-desc">
-    <?js= description ?>
-</div>
-<?js } ?>
-
-<?js if (data.type && data.type.names) {?>
-<dl>
-       <dt>
-               Type
-       </dt>
-       <dd>
-               <?js= this.partial('type.tmpl', data.type.names) ?>
-       </dd>
-</dl>
-<?js } ?>
\ No newline at end of file
diff --git a/scripts/templates/xtuple_specs/tmpl/source.tmpl b/scripts/templates/xtuple_specs/tmpl/source.tmpl
deleted file mode 100644 (file)
index e1092ef..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?js
-    var data = obj;
-?>
-    <section>
-        <article>
-            <pre class="prettyprint source"><code><?js= data.code ?></code></pre>
-        </article>
-    </section>
\ No newline at end of file
diff --git a/scripts/templates/xtuple_specs/tmpl/tutorial.tmpl b/scripts/templates/xtuple_specs/tmpl/tutorial.tmpl
deleted file mode 100644 (file)
index b0c79c1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<section>
-    
-<header>
-    <?js if (children.length > 0) { ?>
-    <ul><?js
-        var self = this;
-        children.forEach(function(t) { ?>
-        <li><?js= self.tutoriallink(t.name) ?></li>
-    <?js }); ?></ul>
-    <?js } ?>
-
-    <h2><?js= header ?></h2>
-</header>  
-
-<article>
-    <?js= content ?>
-</article>
-
-</section>  
diff --git a/scripts/templates/xtuple_specs/tmpl/type.tmpl b/scripts/templates/xtuple_specs/tmpl/type.tmpl
deleted file mode 100644 (file)
index db8194d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?js
-       var data = obj;
-    var self = this;
-    data.forEach(function(name, i) { ?>
-<span class="param-type"><?js= self.linkto(name, self.htmlsafe(name)) ?></span>
-<?js if (i < data.length-1) { ?>|<?js } ?>
-<?js }); ?>
\ No newline at end of file
index 1e14b58..b82f1bd 100644 (file)
@@ -1,5 +1,5 @@
-<package id        = "distribution-install-450"
-         version   = "4.5.0"
+<package id        = "distribution-install-460"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking xTuple ERP database version" >
+                name = "Checking for too-old xTuple ERP database version" >
     <query>SELECT fetchMetricText('ServerVersion') > '4.4.';</query>
     <message>This package must be applied to a 4.4+ Distribution database.
     </message>
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking for bad xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') > '4.5.0' AND fetchMetricText('ServerVersion')!='4.5.0Beta' AND fetchMetricText('ServerVersion')!='4.5.0RC';</query>
-    <message>This package may not be applied to a 4.5+ PostBooks database.
+                name = "Checking for too-new xTuple ERP database version" >
+    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.7.0';</query>
+    <message>This package may not be applied to a database newer than 4.7.0Beta.
     </message>
   </prerequisite>
 
index 48d0027..9ff6ab6 100644 (file)
@@ -1,5 +1,5 @@
-<package id        = "distribution-upgrade-450"
-         version   = "4.5.0"
+<package id        = "distribution-upgrade-460"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking xTuple ERP database version" >
+                name = "Checking for too-old xTuple ERP database version" >
     <query>SELECT fetchMetricText('ServerVersion') > '4.4.';</query>
     <message>This package must be applied to a 4.4+ Distribution database.
     </message>
   </prerequisite>
 
- <prerequisite type = "query"
-               name = "Checking for bad xTuple ERP database version" >
-<query>SELECT NOT fetchMetricText('ServerVersion') > '4.5.0' AND fetchMetricText('ServerVersion')!='4.5.0Beta' AND fetchMetricText('ServerVersion')!='4.5.0RC';</query>
-    <message>This package may not be applied to a 4.5+ Distribution database.
 <prerequisite type = "query"
+                name = "Checking for too-new xTuple ERP database version" >
+    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.7.0';</query>
+    <message>This package may not be applied to a database newer than 4.7.0Beta.
     </message>
   </prerequisite>
 
 
  <prerequisite type = "query"
                name = "Checking for xwd schema" >
-    <query>SELECT NOT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'xwd');</query>
+    <query>SELECT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'xwd');</query>
     <message>This package requires that XWD 240 package to be installed before continuing.</message>
   </prerequisite>
 
+ <prerequisite type = "query"
+               name = "Checking for duplicate Credit Card payments on Sales Orders" >
+    <query>
+      WITH counter AS (SELECT COUNT(*) AS freq
+                        FROM payco
+                        GROUP BY payco_ccpay_id, payco_cohead_id
+                        ORDER BY 1)
+      SELECT (COALESCE(MAX(freq), 1) = 0 OR COALESCE(MAX(freq), 1) = 1)
+      FROM counter;
+    </query>
+    <message>There are duplicate payco_ccpay_id and payco_cohead_id on the payco table. Please see your system administrator or contact xTuple.
+    </message>
+  </prerequisite>
+
+ <prerequisite type="query" name="Checking xwd Package Version">
+     <query>SELECT TRUE FROM pkghead WHERE pkghead_name = 'xwd' AND (pkghead_version >= '2.4');</query>
+    <message>This package must be applied against the 2.4.0 version of the xwd package.</message>
+  </prerequisite>
+
   <script file="postbooks_upgrade.sql" />
   <script file="inventory_upgrade.sql" />
   <script file="distribution_upgrade.sql" />
index b3b8d93..041993b 100644 (file)
@@ -1,5 +1,5 @@
-<package id        = "postbooks-upgrade-450"
-         version   = "4.5.0"
+<package id        = "postbooks-upgrade-460"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking xTuple ERP database version" >
+                name = "Checking for too-old xTuple ERP database version" >
     <query>SELECT fetchMetricText('ServerVersion') > '4.4.';</query>
-    <message>This package must be applied to a 4.4+ PostBooks database.
+    <message>This package must be applied to a 4.4+ database.
     </message>
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking for bad xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') > '4.5.0' AND fetchMetricText('ServerVersion')!='4.5.0Beta' AND fetchMetricText('ServerVersion')!='4.5.0RC';</query>
-    <message>This package may not be applied to a 4.5+ Postbooks database.
+                name = "Checking for too-new xTuple ERP database version" >
+    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.7.0';</query>
+    <message>This package may not be applied to a database newer than 4.7.0Beta.
     </message>
   </prerequisite>
 
     </message>
   </prerequisite>
 
 <prerequisite type = "query"
+ <prerequisite type = "query"
                name = "Checking for duplicate Credit Card payments on Sales Orders" >
     <query>
       WITH counter AS (SELECT COUNT(*) AS freq
                         FROM payco
                         GROUP BY payco_ccpay_id, payco_cohead_id
                         ORDER BY 1)
-      SELECT COALESCE(MAX(freq), 1) <= 1
+      SELECT (COALESCE(MAX(freq), 1) = 0 OR COALESCE(MAX(freq), 1) = 1)
       FROM counter;
     </query>
     <message>There are duplicate payco_ccpay_id and payco_cohead_id on the payco table. Please see your system administrator or contact xTuple.
index 4f7e97b..b6eb595 100644 (file)
@@ -1,5 +1,5 @@
-<package id        = "manufacturing-install-450"
-         version   = "4.5.0"
+<package id        = "manufacturing-install-460"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking xTuple ERP database version" >
+                name = "Checking for too-old xTuple ERP database version" >
     <query>SELECT fetchMetricText('ServerVersion') > '4.4.';</query>
-    <message>This package must be applied to a 4.4+ Distribution database.
+    <message>This package must be applied to a 4.4+ database.
     </message>
   </prerequisite>
 
   <prerequisite type = "query"
-                name = "Checking for bad xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') > '4.5.0' AND fetchMetricText('ServerVersion')!='4.5.0Beta' AND fetchMetricText('ServerVersion')!='4.5.0RC';</query>
-    <message>This package may not be applied to a 4.5.0+ PostBooks database.
+                name = "Checking for too-new xTuple ERP database version" >
+    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.7.0';</query>
+    <message>This package may not be applied to a database newer than 4.7.0Beta.
     </message>
   </prerequisite>
 
index ee7a8b5..ff787b4 100644 (file)
@@ -1,5 +1,5 @@
-<package id        = "manufacturing-upgrade-450"
-         version   = "4.5.0"
+<package id        = "manufacturing-upgrade-460"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
     <message>This package must be applied to an xTuple ERP database that already contains the xtmfg package.</message>
   </prerequisite>
 
+ <prerequisite type="query" name="Checking xtmfg Package Version">
+     <query>SELECT TRUE FROM pkghead WHERE pkghead_name = 'xtmfg' AND (pkghead_version >= '4.4');</query>
+    <message>This package must be applied against the 4.4+ version of the xtmfg package.</message>
+  </prerequisite>
+
   <prerequisite type = "query"
-                name = "Checking xTuple ERP database version" >
+                name = "Checking for too-old xTuple ERP database version" >
     <query>SELECT fetchMetricText('ServerVersion') > '4.4.';</query>
-    <message>This package must be applied to a 4.4+ Manufacturing database.
+    <message>This package must be applied to a 4.4+ database.
     </message>
   </prerequisite>
 
 <prerequisite type = "query"
-               name = "Checking for bad xTuple ERP database version" >
-<query>SELECT NOT fetchMetricText('ServerVersion') > '4.5.0' AND fetchMetricText('ServerVersion')!='4.5.0Beta' AND fetchMetricText('ServerVersion')!='4.5.0RC';</query>
-    <message>This package may not be applied to a 4.5+ Manufacturing database.
+               name = "Checking for too-new xTuple ERP database version" >
+<query>SELECT NOT fetchMetricText('ServerVersion') >= '4.7.0';</query>
+    <message>This package may not be applied to a database newer than 4.7.0Beta.
     </message>
 </prerequisite>
 
index f9ba4ed..f79377e 100644 (file)
@@ -23,24 +23,13 @@ var buildAll = require('../../scripts/lib/build_all'),
       buildAll.build({
         database: databaseName,
         initialize: true,
+        populateData: true,
         source: path.join(__dirname, "../../foundation-database/postbooks_demo_data.sql")
       }, function (err, res) {
         assert.isNull(err);
         done();
       });
     });
-
-    it('should have the POC metric', function (done) {
-      var sql = "select c.metric_id from metric c where c.metric_name = 'UnifiedBuild';";
-
-      creds.database = databaseName;
-      datasource.query(sql, creds, function (err, res) {
-        assert.isNull(err);
-        assert.equal(res.rowCount, 1);
-        done();
-      });
-    });
-
   });
 }());
 
diff --git a/test/database/bankrec.js b/test/database/bankrec.js
new file mode 100644 (file)
index 0000000..b5cd1d3
--- /dev/null
@@ -0,0 +1,1417 @@
+/*jshint trailing:true, white:true, indent:2, strict:true, curly:true,
+  immed:true, eqeqeq:true, forin:true, latedef:true,
+  newcap:true, noarg:true, undef:true */
+/*global XT:true, describe:true, it:true, require:true, __dirname:true, before:true, console:true */
+
+/* note: much of this test consists of SETUP for testing tax handling.
+ * bank reconciliation when cash-based taxation is enabled
+ * is supposed to create taxpay and corresponding gltrans records.
+ * to test this, we need to turn on cashed-based taxation,
+ * generate both a/r and a/p transactions, reconcile the bank
+ * statement, and check the tax history.
+ * reopening the bankrec is supposed to reverse these transactions.
+ */
+
+// TODO: add use of sltrans as well as gltrans
+var _    = require("underscore"),
+  assert = require('chai').assert,
+  path   = require('path');
+
+(function () {
+  "use strict";
+
+  // TODO: implement a real metasql parser; this one is stupid and minimal
+  var mqlToSql = function (query, params) {
+    var result = _.clone(query);
+    _.each(params, function (value, key) {
+      var valueRE = new RegExp("<\\? *value\\(['\"]"   + key + "['\"]\\) *\\?>", "g"),
+        literalRE = new RegExp("<\\? *literal\\(['\"]" + key + "['\"]\\) *\\?>", "g");
+      if (_.isNumber(value)) {
+        result = result.replace(valueRE, value);
+      } else {
+        result = result.replace(valueRE, "'" + value + "'");
+      }
+      result = result.replace(literalRE, value);
+    });
+    return result;
+  };
+
+  describe('test bank reconciliation functions', function () {
+
+    var loginData = require("../lib/login_data.js").data,
+      datasource = require('../../../xtuple/node-datasource/lib/ext/datasource').dataSource,
+      config = require(path.join(__dirname, "../../node-datasource/config.js")),
+      creds  = _.extend({}, config.databaseServer, {database: loginData.org}),
+      start  = new Date(),
+      testTag = 'bankrec test ' + start.toLocaleTimeString(),
+      closeEnough = 0.006,
+      bankaccnt,
+      bankadj = { amount: 54.32 },
+      bankrec,
+      apcheck = {}, apcheckitem,
+      aropen,
+      badTaxIds,
+      cashrcpt,
+      cm,
+      cobmisc = {},
+      cohead, coitem,
+      invchead = {},
+      pohead, poitem,
+      recvid,
+      voucher, voitem,
+      vomisc = { amount: 67.89 },
+      votax,
+      voitemtax,
+      vomisctax,
+      wasCashBasedTax,
+      bankRecItemSql = 'SELECT * FROM bankrecitem '             +
+                       ' WHERE bankrecitem_bankrec_id=<? value("brid") ?>'   +
+                       '   AND bankrecitem_source=<? value("src") ?>'        +
+                       '   AND bankrecitem_source_id <? literal("srcid") ?>;',
+      toggleCheckSql = "SELECT toggleBankRecCleared(<? value('bankrecid') ?>,'GL'," +
+                       "  gltrans_id, checkhead_curr_rate, checkhead_amount)"  +
+                       "  AS result"                                           +
+                       " FROM checkhead JOIN gltrans ON (gltrans_doctype='CK'" +
+                       "                    AND gltrans_misc_id=checkhead_id)" +
+                       " WHERE checkhead_id=<? value('checkid') ?>"            +
+                       "   AND gltrans_amount > 0;",
+      postCheckSql  = "SELECT postCheck(<? value('id') ?>, NULL) AS result;",
+      checkCheckSql = "SELECT *,"                                              +
+                     "       bankrecitem_amount/bankrecitem_curr_rate AS base" +
+                     " FROM gltrans"                                           +
+                     " JOIN bankrecitem ON (gltrans_id=bankrecitem_source_id)" +
+                     " JOIN bankrec    ON (bankrecitem_bankrec_id=bankrec_id)" +
+                     " WHERE gltrans_doctype='CK'"                             +
+                     "   AND gltrans_misc_id=<? value('checkid') ?>"           +
+                     "   AND bankrec_id=<? value('bankrecid') ?>;",
+      bankAdjCheckSql = "SELECT *,"                                           +
+                  " ROUND(bankadj_amount / bankadj_curr_rate, 2) AS baseamt," +
+                  " CASE WHEN gltrans_id IS NULL AND bankrecitem_id IS NULL"  +
+                  "      THEN 0"                                              +
+                  "      WHEN gltrans_id IS NULL OR bankrecitem_id IS NULL"   +
+                  "      THEN 1"                                              +
+                  "      ELSE 2 END AS preferred"                             +
+                  "  FROM bankadj LEFT OUTER"                                 +
+                  "  JOIN gltrans   ON (gltrans_doctype='AD'"                 +
+                  "                 AND gltrans_misc_id=bankadj_id)"          +
+                  "  LEFT OUTER"                                              +
+                  "  JOIN bankrecitem ON (bankrecitem_source='AD'"            +
+                  "                   AND bankrecitem_source_id=bankadj_id)"  +
+                  "                   OR (bankrecitem_source='GL'"            +
+                  "                   AND bankrecitem_source_id=gltrans_id)"  +
+                  " WHERE bankadj_id=<? value('bankadjid') ?>"                +
+                  " ORDER BY preferred DESC LIMIT 1;",
+      getBankRecSql = "SELECT * FROM bankrec WHERE bankrec_id=<? value('id') ?>;",
+      bankRecGLSql = "SELECT gltrans.* "                                       +
+                     "  FROM gltrans"                                          +
+                     "  JOIN bankrecitem ON gltrans_id=bankrecitem_source_id"  +
+                     "                  AND bankrecitem_source='GL'"           +
+                     " WHERE bankrecitem_bankrec_id=<? value('bankrecid') ?>"  +
+                     "   AND bankrecitem_cleared;",
+      postBankRecSql = "SELECT postBankReconciliation(<? value('id') ?>)"  +
+                       "    AS result;",
+      gltransCheckSql = "SELECT COUNT(*) AS cnt FROM gltrans;", // TODO: make smarter
+      taxinfoCheckSql = "SELECT * FROM <? literal('taxhist') ?>"   +
+                        "  LEFT OUTER JOIN taxpay"                 +
+                        "       ON (taxpay_taxhist_id=taxhist_id)" +
+                        " WHERE taxhist_parent_id=<? value('taxparent') ?>;",
+      cohisttaxinfoSql = "SELECT * FROM cohisttax"                             +
+                         "  JOIN cohist ON taxhist_parent_id=cohist_id"        +
+                         "  LEFT OUTER JOIN taxpay"                            +
+                         "       ON taxhist_id=taxpay_taxhist_id"              +
+                         " WHERE cohist_itemsite_id=<? value('itemsite') ?>"   +
+                         "   AND cohist_ordernumber=<? value('cohead') ?>;",
+      lastGltransCount = 0
+    ;
+
+    // set up /////////////////////////////////////////////////////////////////
+
+    it("patches tax accts to ensure tax handling /can/ work", function (done) {
+      var sql = "UPDATE tax SET tax_dist_accnt_id ="            +
+                " (SELECT accnt_id FROM accnt"                  +
+                "   WHERE accnt_descrip = 'Accounts Payable')"  +
+                " WHERE tax_dist_accnt_id IS NULL"              +
+                " RETURNING tax_id;";
+      datasource.query(sql, creds, function (err, res) {
+        assert.isNull(err);
+        badTaxIds = _.map(res.rows, function (v) { return v.tax_id; });
+        done();
+      });
+    });
+
+    it('looks for a bank account to work with', function (done) {
+      var sql = 'SELECT * FROM bankaccnt WHERE bankaccnt_id IN ('       +
+                '   SELECT bankrec_bankaccnt_id FROM bankrec'           +
+                '   GROUP BY bankrec_bankaccnt_id'                      +
+                '   HAVING BOOL_AND(bankrec_posted)) LIMIT 1;'
+                ;
+      datasource.query(sql, creds, function (err, res) {
+        if (res.rowCount === 1) {
+          bankaccnt = res.rows[0];
+          assert.isNotNull(bankaccnt, 'we found a bank account');
+          bankrec = "create";
+          done();
+        } else {
+          var sql = 'SELECT * FROM bankaccnt WHERE bankaccnt_id IN ('       +
+                    '   SELECT bankrec_bankaccnt_id FROM bankrec'           +
+                    '    WHERE bankrec_opendate IN'                         +
+                    '      (SELECT MAX(bankrec_opendate) FROM bankrec'      +
+                    '        WHERE NOT bankrec_posted)'                     +
+                    ') LIMIT 1;'
+                    ;
+          datasource.query(sql, creds, function (err, res) {
+            assert.equal(res.rowCount, 1);
+            bankaccnt = res.rows[0];
+            assert.isNotNull(bankaccnt, 'we found a bank account');
+            bankrec = "select";
+            done();
+          });
+        }
+      });
+    });
+
+    it('ensures there is an open accounting period', function (done) {
+      var sql = 'SELECT period_id, period_closed, period_freeze'        +
+                '  FROM period'                                         +
+                ' WHERE CURRENT_DATE BETWEEN period_start AND period_end;'
+                ;
+      datasource.query(sql, creds, function (err, res) {
+        var sql;
+        if (res.rowCount !== 1) {
+          sql = mqlToSql("INSERT INTO period ("                         +
+                "  period_closed, period_freeze, period_name,"          +
+                "  period_quarter, period_start,"                       +
+                "  period_end, period_number"                           +
+                ") VALUES (FALSE, FALSE, <? value('testTag') ?>,"       +
+                "  EXTRACT(QUARTER FROM DATE CURRENT_DATE),"            +
+                "  DATE_TRUNC(MONTH, CURRENT_DATE),"                    +
+                "  DATE_TRUNC(MONTH, CURRENT_DATE) + '1 month',"        +
+                "  EXTRACT(month FROM DATE CURRENT_DATE)"               +
+                ") RETURNING period_id;",
+                { testTag: testTag });
+        } else if (res.rows[0].period_closed === true) {
+          sql = mqlToSql('SELECT openAccountingPeriod(<? value("period") ?>)' +
+                         ' AS period_id;', { period: res.rows[0].period_id });
+        }
+        if (sql) {
+          datasource.query(sql, creds, function (err, res) {
+            assert.equal(res.rowCount, 1);
+            assert(res.period_id >= 0);
+            done();
+          });
+        } else {
+          done();
+        }
+      });
+    });
+
+    it('turns on cash-based tax handling if necessary', function (done) {
+      var sql = "SELECT fetchMetricBool('CashBasedTax') AS result;";
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        wasCashBasedTax = res.rows[0].result === 't';
+        if (wasCashBasedTax) {
+          done();
+        } else {
+          var sql = "SELECT setMetric('CashBasedTax', 't') AS result;";
+          datasource.query(sql, creds, function (err, res) {
+            assert.equal(res.rowCount, 1);
+            done();
+          });
+        }
+      });
+    });
+
+    it('creates a purchase order', function (done) {
+      var sql = mqlToSql("INSERT INTO pohead (pohead_number, pohead_status,"   +
+                         "  pohead_agent_username, pohead_vend_id,"            +
+                         "  pohead_taxzone_id, pohead_orderdate,"              +
+                         "  pohead_curr_id, pohead_saved, pohead_comments,"    +
+                         "  pohead_warehous_id,"                               +
+                         "  pohead_printed, pohead_terms_id,pohead_taxtype_id" +
+                         ") SELECT fetchPoNumber(), 'U',"                      +
+                         "    CURRENT_USER, vend_id,"                          +
+                         "    vend_taxzone_id, CURRENT_DATE,"                  +
+                         "    vend_curr_id, false, <? value('testTag') ?>,"    +
+                         "    (SELECT MIN(warehous_id) FROM whsinfo WHERE "    +
+                         "     warehous_active AND NOT warehous_transit),"     +
+                         "    false, vend_terms_id, taxass_taxtype_id"         +
+                         "   FROM vendinfo"                                    +
+                         "   JOIN taxass ON vend_taxzone_id=taxass_taxzone_id" +
+                         "   JOIN taxrate ON taxass_tax_id=taxrate_tax_id"     +
+                         "  WHERE vend_active"                                 +
+                         "    AND (taxrate_percent > 0 OR taxrate_amount > 0)" +
+                         " LIMIT 1 RETURNING *;",
+                         { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        pohead = res.rows[0];
+        done();
+      });
+    });
+
+    it('creates a purchase order item', function (done) {
+      var sql = mqlToSql("INSERT INTO poitem (poitem_pohead_id,"               +
+                         "  poitem_linenumber, poitem_status,"                 +
+                         "  poitem_taxtype_id, poitem_itemsite_id,"            +
+                         "  poitem_itemsrc_id, poitem_qty_ordered,"            +
+                         "  poitem_unitprice,"                                 +
+                         "  poitem_duedate, poitem_comments"                   +
+                         ") SELECT pohead_id, 1, 'O',"                         +
+                         "    pohead_taxtype_id, itemsite_id,"                 +
+                         "    itemsrc_id, 100,"                                +
+                         "    itemsrcprice(itemsrc_id, itemsite_warehous_id,"  +
+                         "          false, 100, pohead_curr_id,CURRENT_DATE)," +
+                         "    now() + '5 days', <? value('testTag') ?>"        +
+                         "  FROM pohead"                                       +
+                         "  JOIN itemsrc  ON pohead_vend_id=itemsrc_vend_id"   +
+                         "  JOIN itemsite ON itemsrc_item_id=itemsite_item_id" +
+                         "  WHERE itemsite_active AND itemsrc_active"          +
+                         "    AND pohead_id=<? value('poheadid') ?>"           +
+                         " LIMIT 1 RETURNING *;",
+                         { poheadid: pohead.pohead_id, testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        poitem = res.rows[0];
+        done();
+      });
+    });
+
+    it('calculates purchase order amounts', function (done) {
+      var sql = mqlToSql("SELECT" +
+                         "   SUM(poitem_qty_ordered*poitem_unitprice) AS amt," +
+                         "   SUM(poitem_freight) + pohead_freight AS freight," +
+                         "   (SELECT SUM(tax) FROM"                            +
+                         "      (SELECT ROUND(SUM(taxdetail_tax), 2) AS tax"   +
+                         "         FROM tax JOIN"                              +
+                         "      calculateTaxDetailSummary('PO',pohead_id,'T')" +
+                         "              ON (tax_id=taxdetail_tax_id)"          +
+                         "      GROUP BY tax_id) AS taxdata"                   +
+                         "   ) AS tax"                                         +
+                         "  FROM poitem"                                       +
+                         "  JOIN pohead ON poitem_pohead_id=pohead_id"         +
+                         " WHERE pohead_id=<? value('pohead_id') ?>"           +
+                         " GROUP BY pohead_id, pohead_freight;",
+                         { pohead_id: pohead.pohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        pohead.amount  = res.rows[0].amt;
+        pohead.freight = res.rows[0].freight;
+        pohead.tax     = res.rows[0].tax;
+        apcheck.amount = pohead.amount + pohead.freight + pohead.tax;
+        done();
+      });
+    });
+
+    it('releases the purchase order', function (done) {
+      var sql = mqlToSql("SELECT releasePurchaseOrder(<? value('id') ?>)" +
+                         " AS result;", { id: pohead.pohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0);
+        done();
+      });
+    });
+
+    it('receives the purchase order', function (done) {
+      var sql = mqlToSql("SELECT enterReceipt('PO', poitem_id, 100, 0, ''," +
+                         "   pohead_curr_id, CURRENT_DATE, NULL) AS result" +
+                         "  FROM poitem"                                    +
+                         "  JOIN pohead ON poitem_pohead_id=pohead_id"      +
+                         " WHERE poitem_id=<? value('poitem_id') ?>;",
+                         { poitem_id: poitem.poitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        recvid = res.rows[0].result;
+        done();
+      });
+    });
+
+    it('posts the receipt', function (done) {
+      var sql = mqlToSql("SELECT postReceipt(<? value('recvid') ?>, NULL)" +
+                         " AS result;", { recvid: recvid });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0);
+        done();
+      });
+    });
+
+    it('creates a voucher', function (done) {
+      var sql = mqlToSql("INSERT INTO vohead (vohead_number, vohead_posted,"   +
+                         "  vohead_pohead_id, vohead_taxzone_id,"              +
+                         "  vohead_vend_id,   vohead_terms_id,"                +
+                         "  vohead_distdate,  vohead_docdate, vohead_duedate," +
+                         "  vohead_invcnumber, vohead_reference, vohead_1099," +
+                         "  vohead_amount,     vohead_curr_id,   vohead_notes" +
+                         ") SELECT fetchVoNumber(), false,"                    +
+                         "    pohead_id, pohead_taxzone_id,"                   +
+                         "    pohead_vend_id, pohead_terms_id,"                +
+                         "    CURRENT_DATE, CURRENT_DATE, now() + '30 days',"  +
+                         "    'Vend Invoice', <? value('testTag') ?>, false,"  +
+                         "    <? value('vototal') ?>,"                         +
+                         "    pohead_curr_id, <? value('testTag') ?>"          +
+                         "    FROM pohead"                                     +
+                         "   WHERE pohead_id=<? value('poheadid') ?>"          +
+                         " RETURNING *,"                                       +
+                         "   currRate(vohead_curr_id, CURRENT_DATE) AS exrate;",
+                         { poheadid: pohead.pohead_id,
+                           vototal:  apcheck.amount + vomisc.amount,
+                           testTag:  testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        voucher = res.rows[0];
+        done();
+      });
+    });
+
+    it('distributes the p/o item to the voucher', function (done) {
+      var sql = mqlToSql("SELECT distributeVoucherLine(vohead_id,"          +
+                         "  poitem_id, vohead_curr_id) AS result"           +
+                         "  FROM vohead JOIN poitem"                        +
+                         "          ON (vohead_pohead_id=poitem_pohead_id)" +
+                         " WHERE poitem_id = <? value('poitem_id') ?>;",
+                         { poitem_id: poitem.poitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.equal(res.rows[0].result, 1);
+        done();
+      });
+    });
+
+    it('gets the voitem', function (done) {
+      var sql = mqlToSql("SELECT * FROM voitem" +
+                         " WHERE voitem_vohead_id=<? value('vohead') ?>;",
+                         { vohead: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        voitem = res.rows[0];
+        assert(voitem.voitem_id > 0);
+        done();
+      });
+    });
+
+    it('creates a misc voucher distribution', function (done) {
+      var sql = mqlToSql("INSERT INTO vodist (vodist_vohead_id,"               +
+                         "  vodist_poitem_id, vodist_costelem_id,"             +
+                         "  vodist_accnt_id, vodist_amount,"                   +
+                         "  vodist_discountable, vodist_expcat_id,"            +
+                         "  vodist_tax_id, vodist_notes"                       +
+                         ") SELECT <? value('vohead') ?>, -1, -1,"             +
+                         "    COALESCE(tax_sales_accnt_id,tax_dist_accnt_id)," +
+                         "    <? value('miscamt') ?>,"                         +
+                         "    FALSE, -1, tax_id, <? value('testTag') ?>"       +
+                         "  FROM tax"                                          +
+                         "  JOIN taxass ON tax_id = taxass_tax_id"             +
+                         "  JOIN taxtype ON taxass_taxtype_id=taxtype_id"      +
+                         "  JOIN poitem ON taxtype_id=poitem_taxtype_id"       +
+                         "  JOIN pohead ON poitem_pohead_id=pohead_id"         +
+                         "            AND taxass_taxzone_id=pohead_taxzone_id" +
+                         " WHERE poitem_id=<? value('poitemid') ?>"            +
+                         " RETURNING *;",
+                         { vohead:   voucher.vohead_id, miscamt: vomisc.amount,
+                           poitemid: poitem.poitem_id,  testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        vomisc = res.rows[0];
+        assert(vomisc.vodist_id > 0);
+        done();
+      });
+    });
+
+    it('posts the voucher', function (done) {
+      var sql = mqlToSql("SELECT postVoucher(<? value('id') ?>, TRUE)" +
+                         " AS result;", { id: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0);
+        done();
+      });
+    });
+
+    it('checks for voucher tax distributions', function (done) {
+      var sql = mqlToSql("SELECT 1 AS seq, * FROM voheadtax"                   +
+                         " WHERE taxhist_parent_id=<? value('voheadid') ?>"    +
+                         " UNION ALL "                                         +
+                         "SELECT 2 AS seq, voitemtax.*"                        +
+                         "  FROM voitemtax"                                    +
+                         "  JOIN voitem ON taxhist_parent_id=voitem_id"        +
+                         " WHERE voitem_vohead_id=<? value('voheadid') ?>"     +
+                         " ORDER BY seq, taxhist_id;",
+                         { voheadid: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 2);
+        votax = res.rows[0];
+        assert.closeTo(votax.taxhist_basis, 0, closeEnough);
+        voitemtax = res.rows[1];
+        assert.closeTo(voitemtax.taxhist_basis,
+                       - poitem.poitem_unitprice * poitem.poitem_qty_ordered,
+                       closeEnough);
+        done();
+      });
+    });
+
+    it('creates an apcheck to reconcile', function (done) {
+      var sql = mqlToSql("SELECT createCheck(<? value('bankaccntid') ?>, 'V'," +
+                         "   vohead_vend_id, CURRENT_DATE, vohead_amount,"     +
+                         "   vohead_curr_id, NULL, NULL, 'AP Bearer',"         +
+                         "   <? value('testTag') ?>, TRUE, NULL) AS checkid"   +
+                         "  FROM vohead"                                       +
+                         " WHERE vohead_id=<? value('voheadid') ?>;",
+                         { bankaccntid: bankaccnt.bankaccnt_id,
+                           voheadid:    voucher.vohead_id,
+                           testTag:     testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].checkid > 0);
+        var checkid = res.rows[0].checkid;
+        sql = mqlToSql("UPDATE checkhead SET checkhead_number="      +
+                       "  fetchNextCheckNumber(<? value('bank') ?>)" +
+                       " WHERE checkhead_id=<? value('check') ?>"    +
+                       " RETURNING *;",
+                       { bank: bankaccnt.bankaccnt_id, check: checkid });
+        datasource.query(sql, creds, function (err, res) {
+          assert.equal(res.rowCount, 1);
+          apcheck = res.rows[0];
+          done();
+        });
+      });
+    });
+
+    it('creates a credit memo to attach to the apcheck', function (done) {
+      var sql = mqlToSql("SELECT createAPCreditMemo(NULL, pohead_vend_id,"     +
+                         "       fetchJournalNumber('AP-MISC'),"               +
+                         "       <? value('vonumber') ?>, pohead_number,"      +
+                         "       CURRENT_DATE, <? value('amount') ?>,"         +
+                         "       <? value('testTag') ?>, -1,"                  +
+                         "       CAST(now()+'30 days' AS DATE),"               +
+                         "       pohead_terms_id, pohead_curr_id) AS result"   +
+                         "  FROM pohead"                                       +
+                         " WHERE pohead_id=<? value('poheadid') ?>;",
+                         { amount:   apcheck.checkhead_amount,
+                           testTag:  testTag,
+                           vonumber: voucher.vohead_number,
+                           poheadid: pohead.pohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        cm = res.rows[0].result;
+        assert(cm > 0);
+        done();
+      });
+    });
+
+    it('creates a checkitem for the credit memo', function (done) {
+      var sql = mqlToSql("INSERT INTO checkitem ("                             +
+                         "  checkitem_checkhead_id, checkitem_apopen_id,"      +
+                         "  checkitem_vouchernumber, checkitem_amount,"        +
+                         "  checkitem_ponumber, checkitem_discount,"           +
+                         "  checkitem_docdate,"                                +
+                         "  checkitem_curr_id, checkitem_curr_rate"            +
+                         ") SELECT <? value('checkid') ?>, apopen_id,"         +
+                         "    <? value('vonumber') ?>, apopen_amount,"         +
+                         "    apopen_ponumber, 0, CURRENT_DATE,"               +
+                         "    apopen_curr_id, apopen_curr_rate"                +
+                         "  FROM apopen"                                       +
+                         " WHERE apopen_journalnumber=<? value('journal') ?>"  +
+                         " RETURNING *;",
+                         { checkid: apcheck.checkhead_id,
+                           vonumber: voucher.vohead_number,
+                           journal: cm });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        apcheckitem = res.rows[0];
+        assert(apcheckitem.checkitem_id > 0);
+        done();
+      });
+    });
+
+    it('posts the apcheck', function (done) {
+      var sql = mqlToSql(postCheckSql, { id: apcheck.checkhead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0);
+        apcheck.journalNumber = res.rows[0].result;
+        done();
+      });
+    });
+
+    it('creates a sales order', function (done) {
+      var sql = mqlToSql("INSERT INTO cohead (cohead_number, cohead_cust_id,"  +
+                 "    cohead_orderdate, cohead_packdate,"                      +
+                 "    cohead_shipto_id, cohead_shiptoname,"                    +
+                 "    cohead_shiptoaddress1, cohead_shiptoaddress2,"           +
+                 "    cohead_shiptoaddress3, cohead_shiptocity,"               +
+                 "    cohead_shiptostate, cohead_shiptozipcode,"               +
+                 "    cohead_shiptocountry, cohead_ordercomments,"             +
+                 "    cohead_salesrep_id, cohead_terms_id, cohead_holdtype,"   +
+                 "    cohead_freight, cohead_calcfreight,"                     +
+                 "    cohead_shipto_cntct_id, cohead_shipto_cntct_first_name," +
+                 "    cohead_shipto_cntct_last_name,"                          +
+                 "    cohead_curr_id, cohead_taxzone_id, cohead_taxtype_id,"   +
+                 "    cohead_saletype_id,"                                     +
+                 "    cohead_shipvia,"                                         +
+                 "    cohead_shipchrg_id,"                                     +
+                 "    cohead_shipzone_id, cohead_shipcomplete"                 +
+                 ") SELECT fetchSoNumber(), cust_id,"                          +
+                 "    CURRENT_DATE, CURRENT_DATE,"                             +
+                 "    shipto_id, shipto_name,"                                 +
+                 "    addr_line1, addr_line2,"                                 +
+                 "    addr_line3, addr_city,"                                  +
+                 "    addr_state, addr_postalcode,"                            +
+                 "    addr_country, <? value('testTag') ?>,"                   +
+                 "    cust_salesrep_id, cust_terms_id, 'N',"                   +
+                 "    0, TRUE,"                                                +
+                 "    cntct_id, cntct_first_name, cntct_last_name,"            +
+                 "    cust_curr_id, shipto_taxzone_id, taxass_taxtype_id,"     +
+                 "    (SELECT saletype_id FROM saletype"                       +
+                 "      WHERE saletype_code='REP'),"                           +
+                 "    (SELECT MIN(shipvia_code) FROM shipvia),"                +
+                 "    (SELECT shipchrg_id FROM shipchrg"                       +
+                 "      WHERE shipchrg_name='ADDCHARGE'),"                     +
+                 "    shipto_shipzone_id, FALSE"                               +
+                 "  FROM custinfo"                                             +
+                 "  JOIN shiptoinfo ON cust_id=shipto_cust_id"                 +
+                 "                 AND shipto_active"                          +
+                 "  JOIN taxass ON shipto_taxzone_id=taxass_taxzone_id"        +
+                 "  JOIN taxrate ON taxass_tax_id=taxrate_tax_id"              +
+                 "  LEFT OUTER JOIN addr ON shipto_addr_id=addr_id"            +
+                 "  LEFT OUTER JOIN cntct ON shipto_cntct_id=cntct_id"         +
+                 " WHERE cust_active"                                          +
+                 "   AND cust_preferred_warehous_id > 0"                       +
+                 "   AND (taxrate_percent > 0 OR taxrate_amount > 0)"          +
+                 " LIMIT 1 RETURNING *;",
+                 { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        cohead = res.rows[0];
+        assert(cohead.cohead_id > 0);
+        done();
+      });
+    });
+
+    it('creates a sales order item', function (done) {
+      var sql = mqlToSql("INSERT INTO coitem (coitem_cohead_id,"              +
+               "    coitem_linenumber, coitem_scheddate, coitem_itemsite_id," +
+               "    coitem_taxtype_id, coitem_status,"                        +
+               "    coitem_qtyord, coitem_qtyshipped,  coitem_qtyreturned,"   +
+               "    coitem_unitcost, coitem_price, coitem_custprice,"         +
+               "    coitem_qty_uom_id, coitem_price_uom_id,"                  +
+               "    coitem_qty_invuomratio, coitem_price_invuomratio"         +
+               ") SELECT cohead_id,"                                          +
+               "    1, CURRENT_DATE + itemsite_leadtime, itemsite_id,"        +
+               "    getItemTaxType(item_id, cohead_taxzone_id), 'O',"         +
+               "    123, 0, 0,"                                               +
+               "    itemcost(itemsite_id), item_listprice, item_listprice,"   +
+               "    item_price_uom_id, item_price_uom_id,"                    +
+               "    1, 1"                                                     +
+               "  FROM cohead"                                                +
+               "  JOIN custinfo ON cohead_cust_id=cust_id"                    +
+               "  JOIN itemsite"                                              +
+               "        ON cust_preferred_warehous_id=itemsite_warehous_id"   +
+               "  JOIN item ON (itemsite_item_id=item_id)"                    +
+               " WHERE cohead_id=<? value('coheadid') ?>"                     +
+               "   AND itemsite_active"                                       +
+               "   AND item_active"                                           +
+               "   AND item_sold"                                             +
+               "   AND NOT item_exclusive"                                    +
+               "   AND NOT item_exclusive"                                    +
+               "   AND ("                                                     +
+               "         SELECT itemprice_price"                              +
+               "         FROM itemipsprice("                                  +
+               "           item_id,"                                          +
+               "           cohead_cust_id,"                                   +
+               "           cohead_shipto_id,"                                 +
+               "           123,"                                              +
+               "           item_price_uom_id,"                                +
+               "           item_price_uom_id,"                                +
+               "           basecurrid(),"                                     +
+               "           CURRENT_DATE,"                                     +
+               "           CURRENT_DATE,"                                     +
+               "           itemsite_warehous_id"                              +
+               "         )"                                                   +
+               "       ) > 0 "                                                +
+               "   AND item_price_uom_id=item_inv_uom_id"                     +
+/* simplify!*/ "   AND item_type != 'K'"                                      +
+               " LIMIT 1 RETURNING *;",
+                 { coheadid: cohead.cohead_id, testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        coitem = res.rows[0];
+        assert(coitem.coitem_id > 0);
+        done();
+      });
+    });
+
+    it('updates the sales order with item info', function (done) {
+      var sql = mqlToSql("UPDATE cohead SET cohead_freight=("                  +
+                         "    SELECT SUM(freightdata_total)"                   +
+                         "      FROM freightDetail('SO', cohead_id,"           +
+                         "              cohead_cust_id, cohead_shipto_id,"     +
+                         "              CURRENT_DATE, cohead_shipvia,"         +
+                         "              cohead_curr_id))"                      +
+                         " WHERE cohead_id=<? value('cohead_id') ?>"           +
+                         " RETURNING cohead_freight;",
+                         { cohead_id: cohead.cohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        cohead.cohead_freight = res.rows[0].cohead_freight;
+        done();
+      });
+    });
+
+    it('calculates sales order amounts', function (done) {
+      var sql = mqlToSql("SELECT SUM(coitem_qtyord*coitem_price) AS amt,"      +
+                         "   (SELECT SUM(tax) FROM"                            +
+                         "      (SELECT ROUND(SUM(taxdetail_tax), 2) AS tax"   +
+                         "         FROM tax JOIN"                              +
+                         "      calculateTaxDetailSummary('S',cohead_id,'T')"  +
+                         "              ON (tax_id=taxdetail_tax_id)"          +
+                         "      GROUP BY tax_id) AS taxdata"                   +
+                         "   ) AS tax"                                         +
+                         "  FROM coitem"                                       +
+                         "  JOIN cohead ON coitem_cohead_id=cohead_id"         +
+                         " WHERE cohead_id=<? value('cohead_id') ?>"           +
+                         " GROUP BY cohead_id;",
+                         { cohead_id: cohead.cohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        cohead.subtotal = res.rows[0].amt;
+        cohead.tax      = res.rows[0].tax;
+        cohead.amount   = cohead.subtotal + cohead.cohead_freight + cohead.tax;
+        assert(cohead.subtotal > 0, 'expect the sales order to have value');
+        assert(cohead.tax      > 0, 'expect the sales order to have tax');
+        done();
+      });
+    });
+
+    it('issue the sales order to shipping', function (done) {
+      var sql = mqlToSql("SELECT issueToShipping(coitem_id, coitem_qtyord)" +
+                         "       AS result"                                 +
+                         "  FROM coitem WHERE coitem_id=<? value('id') ?>;",
+                         { id: coitem.coitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0, 'expected issueToShipping to succeed');
+        done();
+      });
+    });
+
+    it('ships the sales order', function (done) {
+      var sql = mqlToSql("SELECT shipShipment(shiphead_id) AS result"          +
+                         "  FROM shiphead"                                     +
+                         "  JOIN shipitem ON shiphead_order_type = 'SO'"       +
+                         "               AND shiphead_id=shipitem_shiphead_id" +
+                         " WHERE shipitem_orderitem_id=<? value('coitem') ?>;",
+                         { coitem: coitem.coitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        // TODO: why does shipShipment return NULL on success?
+        assert(res.rows[0].result === null || res.rows[0].result > 0,
+               'expected shipShipment to succeed');
+        done();
+      });
+    });
+
+    // this creates cobmisc and cobill records for all uninvoiced coitems
+    it('selects the shipment for billing', function (done) {
+      var sql = mqlToSql("SELECT selectUninvoicedShipment(shiphead_id)"        +
+                         "       AS result"                                    +
+                         "  FROM shiphead"                                     +
+                         "  JOIN shipitem ON shiphead_order_type = 'SO'"       +
+                         "               AND shiphead_id=shipitem_shiphead_id" +
+                         " WHERE shipitem_orderitem_id=<? value('coitem') ?>;",
+                         { coitem: coitem.coitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        cobmisc.cobmisc_id = res.rows[0].result;
+        assert(cobmisc.cobmisc_id > 0,
+               'expected selectUninvoicedShipment to succeed');
+        done();
+      });
+    });
+
+    it('creates an invoice', function (done) {
+      var sql = mqlToSql("SELECT createInvoice(<? value('cobmisc') ?>) AS id;",
+                         { cobmisc: cobmisc.cobmisc_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        invchead.invchead_id = res.rows[0].id;
+        assert(invchead.invchead_id > 0, 'expected createInvoice to succeed');
+        done();
+      });
+    });
+
+    it('posts the invoice', function (done) {
+      var sql = mqlToSql("SELECT postInvoice(<? value('id') ?>) AS result;",
+                         { id: invchead.invchead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        var result = res.rows[0].result;
+        assert(result === null || result > 0, 'expected postInvoice to succeed');
+        done();
+      });
+    });
+
+    // TODO? UPDATE shipdatasum SET shipdatasum_shipped=true
+    //        WHERE shipdatasum_cosmisc_tracknum = ''
+    //          AND shipdatasum_shiphead_number='60103';
+
+    it('creates a cash receipt to reconcile', function (done) {
+      var sql = mqlToSql("INSERT INTO cashrcpt ("                              +
+                         "  cashrcpt_cust_id, cashrcpt_amount,"                +
+                         "  cashrcpt_fundstype, cashrcpt_docnumber,"           +
+                         "  cashrcpt_bankaccnt_id, cashrcpt_notes,"            +
+                         "  cashrcpt_curr_id, cashrcpt_number,"                +
+                         "  cashrcpt_docdate, cashrcpt_applydate,"             +
+                         "  cashrcpt_distdate, cashrcpt_usecustdeposit,"       +
+                         "  cashrcpt_curr_rate,"                               +
+                         "  cashrcpt_salescat_id, cashrcpt_discount"           +
+                         ") SELECT cohead_cust_id, <? value('amount') ?>,"     +
+                         "       'C', 'CR ' || <? value('testTag') ?>,"        +
+                         "       <? value('bank') ?>, <? value('testTag') ?>," +
+                         "       cohead_curr_id, fetchCashRcptNumber(),"       +
+                         "       NULL, CURRENT_DATE,"                          +
+                         "       CURRENT_DATE, TRUE,"                          +
+                         "       currRate(cohead_curr_id, CURRENT_DATE),"      +
+                         "       -1, 0"                                        +
+                         "    FROM cohead"                                     +
+                         "   WHERE cohead_id=<? value('coheadid') ?>"          +
+                         " RETURNING *;",
+                         { coheadid: cohead.cohead_id,
+                           amount:   cohead.amount,
+                           bank:     bankaccnt.bankaccnt_id,
+                           testTag:  testTag
+                         });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].cashrcpt_id > 0);
+        cashrcpt = res.rows[0];
+        done();
+      });
+    });
+
+    it('apply the cash receipt to the invoice', function (done) {
+      var sql = mqlToSql("SELECT applyCashReceiptLineBalance("                 +
+                         "     <? value('crid') ?>, aropen_id, aropen_amount," +
+                         "     aropen_curr_id) AS result"                      +
+                         "  FROM aropen"                                       +
+                         "  JOIN invchead ON aropen_doctype = 'I'"             +
+                         "           AND aropen_docnumber=invchead_invcnumber" +
+                         " WHERE invchead_id=<? value('invchead') ?>;",
+                         { crid:     cashrcpt.cashrcpt_id,
+                           invchead: invchead.invchead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result > 0, 'expect an application');
+        // applyCashReceiptLineBalance subtracts discounts so we can't just
+        // assert.closeTo(res.rows[0].result, cohead.amount, closeEnough);
+        done();
+      });
+    });
+
+    // This creates an aropen and a cashrcptitem
+    it('posts the cash receipt', function (done) {
+      var sql = mqlToSql("SELECT postCashReceipt(<? value('id') ?>," +
+                         "    fetchJournalNumber('C/R')) AS result;",
+                         { id: cashrcpt.cashrcpt_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.equal(res.rows[0].result, 1);
+        done();
+      });
+    });
+
+    it('finds the aropen for the cash receipt application', function (done) {
+      var sql = mqlToSql("SELECT aropen.* FROM aropen JOIN cashrcptitem"     +
+                         "    ON aropen_id=cashrcptitem_aropen_id"           +
+                         " WHERE cashrcptitem_cashrcpt_id=<? value('id') ?>" +
+                         "   AND aropen_doctype = 'I';",
+                         { id: cashrcpt.cashrcpt_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        aropen = res.rows[0];
+        done();
+      });
+    });
+
+    // now start actual bankrec testing ///////////////////////////////////////
+
+    it('gets an open bankrec to test with', function (done) {
+      var mql, sql;
+      if (bankrec === "create") {
+        mql = 'INSERT INTO bankrec (bankrec_bankaccnt_id,'    +
+              '  bankrec_opendate, bankrec_openbal'           +
+              ') SELECT bankrec_bankaccnt_id,'                +
+              '         bankrec_enddate + 1, bankrec_endbal'  +
+              '    FROM bankrec'                              +
+              '   WHERE bankrec_bankaccnt_id=<? value("bankaccnt") ?>' +
+              '     AND bankrec_posted'                       +
+              '   ORDER BY bankrec_enddate DESC'              +
+              '   LIMIT 1 RETURNING *;'
+              ;
+      } else if (bankrec === "select") {
+        mql = 'SELECT * FROM bankrec'                                    +
+              ' WHERE bankrec_bankaccnt_id=<? value("bankaccnt") ?>'     +
+              '   AND bankrec_opendate IN'                               +
+              '  (SELECT MAX(bankrec_opendate) FROM bankrec'             +
+              '    WHERE NOT bankrec_posted'                             +
+              '      AND bankrec_bankaccnt_id=<? value("bankaccnt") ?>'  +
+              '  );'
+              ;
+      }
+      sql = mqlToSql(mql, {bankaccnt: bankaccnt.bankaccnt_id});
+
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        bankrec = res.rows[0];
+        assert.isNotNull(bankrec,              'we have a bank rec');
+        assert.isFalse(bankrec.bankrec_posted, 'we have an open bank rec');
+        done();
+      });
+    });
+
+    it('marks the apcheck as cleared', function (done) {
+      var sql = mqlToSql(toggleCheckSql, { bankrecid: bankrec.bankrec_id,
+                                           checkid:   apcheck.checkhead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].result);
+        done();
+      });
+    });
+
+    it('confirms the apcheck was marked as cleared', function (done) {
+      var sql = mqlToSql(bankRecItemSql,
+        { brid: bankrec.bankrec_id, src: 'GL',
+          srcid: " IN (SELECT gltrans_id FROM gltrans WHERE"  +
+                 " gltrans_doctype='CK' AND gltrans_misc_id=" +
+                 apcheck.checkhead_id + ")"});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankrecitem_cleared);
+        assert(res.rows[0].bankrecitem_cleared);
+        done();
+      });
+    });
+
+    it('marks the apcheck as /not/ cleared', function (done) {
+      var sql = mqlToSql(toggleCheckSql, { bankrecid: bankrec.bankrec_id,
+                                           checkid:   apcheck.checkhead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isFalse(res.rows[0].result);
+        done();
+      });
+    });
+
+    it('confirms the apcheck is no longer marked as cleared', function (done) {
+      var sql = mqlToSql(bankRecItemSql,
+        { brid: bankrec.bankrec_id, src: 'GL',
+          srcid: " IN (SELECT gltrans_id FROM gltrans WHERE"  +
+                 " gltrans_doctype='CK' AND gltrans_misc_id=" +
+                 apcheck.checkhead_id + ")" });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 0);
+        done();
+      });
+    });
+
+    it('marks the apcheck as cleared again', function (done) {
+      var sql = mqlToSql(toggleCheckSql, { bankrecid: bankrec.bankrec_id,
+                                           checkid:   apcheck.checkhead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].result);
+        done();
+      });
+    });
+
+    it('confirms that the apcheck is marked as cleared again', function (done) {
+      var sql = mqlToSql(bankRecItemSql,
+        { brid: bankrec.bankrec_id, src: 'GL',
+          srcid: " IN (SELECT gltrans_id FROM gltrans" +
+                 " WHERE gltrans_doctype='CK' AND "    +
+                 " gltrans_misc_id=" + apcheck.checkhead_id + ")"});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankrecitem_cleared);
+        assert(res.rows[0].bankrecitem_cleared);
+        done();
+      });
+    });
+
+    it('marks the cash receipt as cleared', function (done) {
+      var sql = mqlToSql("SELECT toggleBankRecCleared("                        +
+                         "     <? value('bankrecid') ?>, 'A/R', gltrans_id,"   +
+                         "     cashrcpt_curr_rate, cashrcpt_amount) AS result" +
+                         "  FROM gltrans"                                      +
+                         "  JOIN cashrcpt ON gltrans_misc_id=cashrcpt_id"      +
+                         "               AND gltrans_doctype='CR'"             +
+                         " WHERE cashrcpt_id=<? value('cashrcptid') ?>"        +
+                         "   AND gltrans_accnt_id=<? value('accntid') ?>;",
+                         { bankrecid: bankrec.bankrec_id,
+                           cashrcptid:  cashrcpt.cashrcpt_id,
+                           accntid:   bankaccnt.bankaccnt_accnt_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].result);
+        done();
+      });
+    });
+
+    it('confirms the cash receipt was marked as cleared', function (done) {
+      var sql = mqlToSql(bankRecItemSql,
+        { brid: bankrec.bankrec_id, src: 'A/R',
+          srcid: " IN (SELECT gltrans_id FROM gltrans WHERE"  +
+                 " gltrans_doctype='CR' AND gltrans_misc_id=" +
+                 cashrcpt.cashrcpt_id + ")" });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankrecitem_cleared);
+        assert(res.rows[0].bankrecitem_cleared);
+        done();
+      });
+    });
+
+    it('creates a bank adjustment', function (done) {
+      var sql = mqlToSql("INSERT INTO bankadj ("                             +
+                "  bankadj_bankaccnt_id, bankadj_bankadjtype_id,"            +
+                "  bankadj_date, bankadj_docnumber, bankadj_amount,"         +
+                "  bankadj_notes, bankadj_curr_id,"                          +
+                "  bankadj_curr_rate"                                        +
+                ") SELECT <? value('bankaccnt') ?>, bankadjtype_id,"         +
+                "    CURRENT_DATE, 'BankRecTest', <? value('amount') ?>,"    +
+                "    <? value('testTag') ?>,      <? value('currid') ?>,"    +
+                "    currrate(<? value('currid') ?>, basecurrid(),"          +
+                "             CURRENT_DATE) FROM bankadjtype RETURNING *;",
+                { amount: bankadj.amount, bankaccnt: bankaccnt.bankaccnt_id,
+                  testTag: testTag,      currid: bankaccnt.bankaccnt_curr_id })
+                ;
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        _.extend(bankadj, res.rows[0]);
+        assert.ok(bankadj.bankadj_id, 'we have a bank adjustment');
+        done();
+      });
+    });
+
+    it('gets the size of the gltrans table before posting', function (done) {
+      var sql = mqlToSql(gltransCheckSql, { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        lastGltransCount = res.rows[0].cnt;
+        done();
+      });
+    });
+
+    it('checks voitem tax data before posting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voitemtax', taxparent: voitem.voitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect one voitemtax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no voitem taxpay');
+        done();
+      });
+    });
+
+    it('checks misc distrib tax data before posting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voheadtax', taxparent: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect one voheadtax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no vohead taxpay');
+        done();
+      });
+    });
+
+    it('checks cashrcpt application tax data before posting', function (done) {
+      var sql = mqlToSql(cohisttaxinfoSql,
+                         { itemsite: coitem.coitem_itemsite_id,
+                           cohead:   cohead.cohead_number });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect 1 cohisttax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no cohist taxpay');
+        done();
+      });
+    });
+
+    it('posts the reconciliation', function (done) {
+      var sql = mqlToSql(postBankRecSql, {id: bankrec.bankrec_id});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.equal(res.rows[0].result, bankrec.bankrec_id);
+        done();
+      });
+    });
+
+    it('confirms the posted bankrec was updated properly', function (done) {
+      var sql = mqlToSql(getBankRecSql, { id: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankrec_posted);
+        assert.isNotNull(res.rows[0].bankrec_postdate, 'expect a post date');
+        done();
+      });
+    });
+
+    it('confirms the gl for the posted bankrec was updated', function (done) {
+      var sql = mqlToSql(bankRecGLSql, { bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        var recorded = _.filter(res.rows,
+                                function (v) { return v.gltrans_rec; });
+        assert.equal(res.rows.length, recorded.length, 'AND(gltrans_rec) should be true');
+        done();
+      });
+    });
+
+    it('confirms the apcheck was reconciled properly', function (done) {
+      var sql = mqlToSql(checkCheckSql, { checkid:   apcheck.checkhead_id,
+                                          bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].gltrans_rec);
+        assert.isTrue(res.rows[0].bankrec_posted);
+        assert.closeTo(res.rows[0].gltrans_amount,
+                       apcheck.checkhead_amount / apcheck.checkhead_curr_rate,
+                       closeEnough);
+        done();
+      });
+    });
+
+    it('confirms reconcile updated gltrans properly', function (done) {
+      var sql = mqlToSql(gltransCheckSql, { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert(res.rows[0].cnt > lastGltransCount, 'expected tax records');
+        lastGltransCount = res.rows[0].cnt;
+        done();
+      });
+    });
+
+    it('checks voitem tax data after posting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voitemtax', taxparent: voitem.voitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect 1 voitemtax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a voitem taxpay');
+        assert.closeTo(res.rows[0].taxpay_tax, voitemtax.taxhist_tax, closeEnough);
+        done();
+      });
+    });
+
+    it('checks misc distrib tax data after posting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voheadtax', taxparent: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect a vodisttax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a vodist taxpay');
+        assert.closeTo(res.rows[0].taxpay_tax, votax.taxhist_tax, closeEnough);
+        done();
+      });
+    });
+
+    it('checks cashrcpt application tax data after posting', function (done) {
+      var sql = mqlToSql(cohisttaxinfoSql,
+                         { itemsite: coitem.coitem_itemsite_id,
+                           cohead:   cohead.cohead_number });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect a cohisttax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a cohist taxpay');
+        // discount => can't assert.closeTo(res.rows[0].taxpay_tax ...
+        done();
+      });
+    });
+
+    it('confirms the bank adjustment was /not/ posted', function (done) {
+      var sql = mqlToSql(bankAdjCheckSql, { bankadjid: bankadj.bankadj_id});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isFalse(res.rows[0].bankadj_posted);
+        assert.isNull(res.rows[0].gltrans_id,     'expecting no gltrans');
+        assert.isNull(res.rows[0].bankrecitem_id, 'expecting no bankrecitem');
+        done();
+      });
+    });
+
+    it('reopens the reconcilation', function (done) {
+      var sql = 'SELECT reopenBankReconciliation(' + bankrec.bankrec_id +
+                ') AS result;';
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.equal(res.rows[0].result, bankrec.bankrec_id);
+        done();
+      });
+    });
+
+    it('confirms the reopened bankrec was updated properly', function (done) {
+      var sql = mqlToSql(getBankRecSql, { id: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isFalse(res.rows[0].bankrec_posted);
+        assert.isNull(res.rows[0].bankrec_postdate, 'expect empty post date');
+        done();
+      });
+    });
+
+    it('confirms the gl for the reopened bankrec was updated', function (done) {
+      var sql = mqlToSql(bankRecGLSql, { bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        var recorded = _.filter(res.rows,
+                                function (v) { return v.gltrans_rec; });
+        assert.equal(0, recorded.length, 'AND(gltrans_rec) should be true');
+        done();
+      });
+    });
+
+    it('confirms reconcile updated gltrans properly', function (done) {
+      var sql = mqlToSql(gltransCheckSql, { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert(res.rows[0].cnt > lastGltransCount, 'expected tax reversals');
+        lastGltransCount = res.rows[0].cnt;
+        done();
+      });
+    });
+
+    it('checks voitem tax data after reopening', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voitemtax', taxparent: voitem.voitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect one voitemtax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no voitem taxpay');
+        done();
+      });
+    });
+
+    it('checks misc distrib tax data after reopening', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voheadtax', taxparent: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect one voheadtax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no vohead taxpay');
+        done();
+      });
+    });
+
+    it('checks cashrcpt application tax data after reopening', function (done) {
+      var sql = mqlToSql(cohisttaxinfoSql,
+                         { itemsite: coitem.coitem_itemsite_id,
+                           cohead:   cohead.cohead_number });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,        'expect 1 cohisttax record');
+        assert.isNull(res.rows[0].taxpay_id, 'expect no cohist taxpay');
+        done();
+      });
+    });
+
+    it('confirms the apcheck was "reopened" properly', function (done) {
+      var sql = mqlToSql(checkCheckSql, { checkid:   apcheck.checkhead_id,
+                                          bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isFalse(res.rows[0].gltrans_rec);
+        assert.isFalse(res.rows[0].bankrec_posted);
+        assert.closeTo(Math.abs(res.rows[0].gltrans_amount), res.rows[0].base,
+                       closeEnough);
+        done();
+      });
+    });
+
+    // we expect the reconcile to create gltrans records for voitem tax
+    it('confirms unreconcile updated gltrans properly', function (done) {
+      var sql = mqlToSql(gltransCheckSql, { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+// TODO assert(res.rows[0].cnt > lastGltransCount, 'expected new gltrans');
+        lastGltransCount = res.rows[0].cnt;
+        done();
+      });
+    });
+
+    it('marks the bank adjustment as cleared', function (done) {
+      var sql = "SELECT toggleBankRecCleared(" + bankrec.bankrec_id         +
+                ", 'AD', " + bankadj.bankadj_id        +
+                ", " + bankadj.bankadj_curr_rate       +
+                ", " + bankadj.bankadj_amount + ") AS result;"
+                ;
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].result);
+        done();
+      });
+    });
+
+    it('confirms the bank adjustment was /not/ posted but is cleared', function (done) {
+      var sql = mqlToSql(bankAdjCheckSql, { bankadjid: bankadj.bankadj_id});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isFalse(res.rows[0].bankadj_posted);
+        assert(res.rows[0].bankrecitem_id >= 0);
+        done();
+      });
+    });
+
+    it('posts the reconciliation again', function (done) {
+      var sql = mqlToSql(postBankRecSql, {id: bankrec.bankrec_id});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.equal(res.rows[0].result, bankrec.bankrec_id);
+        done();
+      });
+    });
+
+    it('confirms the 2nd posted bankrec was updated properly', function (done) {
+      var sql = mqlToSql(getBankRecSql, { id: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankrec_posted);
+        assert.isNotNull(res.rows[0].bankrec_postdate, 'expect a post date');
+        done();
+      });
+    });
+
+    it('confirms the gl for 2nd posted bankrec was updated', function (done) {
+      var sql = mqlToSql(bankRecGLSql, { bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        var recorded = _.filter(res.rows,
+                                function (v) { return v.gltrans_rec; });
+        assert.equal(res.rows.length, recorded.length, 'AND(gltrans_rec) should be true');
+        done();
+      });
+    });
+
+    it('confirms the apcheck was reconciled properly', function (done) {
+      var sql = mqlToSql(checkCheckSql, { checkid:   apcheck.checkhead_id,
+                                          bankrecid: bankrec.bankrec_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].gltrans_rec);
+        assert.isTrue(res.rows[0].bankrec_posted);
+        assert.closeTo(res.rows[0].gltrans_amount,
+                       apcheck.checkhead_amount / apcheck.checkhead_curr_rate,
+                       closeEnough);
+        done();
+      });
+    });
+
+    it('confirms reposting updated gltrans properly', function (done) {
+      var sql = mqlToSql(gltransCheckSql, { testTag: testTag });
+      datasource.query(sql, creds, function (err, res) {
+        assert(res.rows[0].cnt > lastGltransCount, 'expected new tax records');
+        lastGltransCount = res.rows[0].cnt;
+        done();
+      });
+    });
+
+    it('checks voitem tax data after reposting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voitemtax', taxparent: voitem.voitem_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect 1 voitemtax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a voitem taxpay');
+        assert.closeTo(res.rows[0].taxpay_tax, voitemtax.taxhist_tax, closeEnough);
+        done();
+      });
+    });
+
+    it('checks misc distrib tax data after reposting', function (done) {
+      var sql = mqlToSql(taxinfoCheckSql,
+                         { taxhist: 'voheadtax', taxparent: voucher.vohead_id });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect a vodisttax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a vodist taxpay');
+        assert.closeTo(res.rows[0].taxpay_tax, votax.taxhist_tax, closeEnough);
+        done();
+      });
+    });
+
+    it('checks cashrcpt application tax data after reposting', function (done) {
+      var sql = mqlToSql(cohisttaxinfoSql,
+                         { itemsite: coitem.coitem_itemsite_id,
+                           cohead:   cohead.cohead_number });
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1,           'expect a cohisttax record');
+        assert.isNotNull(res.rows[0].taxpay_id, 'expect a cohist taxpay');
+        // discount => can't assert.closeTo(res.rows[0].taxpay_tax ...
+        done();
+      });
+    });
+
+    it('confirms the bank adj was posted & written to the GL', function (done) {
+      var sql = mqlToSql(bankAdjCheckSql, { bankadjid: bankadj.bankadj_id});
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert.isTrue(res.rows[0].bankadj_posted);
+        assert(res.rows[0].bankadj_sequence >= 0);
+        assert.equal(res.rows[0].bankrecitem_source, 'GL');
+        assert.equal(res.rows[0].bankrecitem_source_id, res.rows[0].gltrans_id);
+        assert.isTrue(res.rows[0].gltrans_rec);
+        assert.closeTo(Math.abs(res.rows[0].gltrans_amount),
+                       res.rows[0].baseamt, closeEnough);
+        done();
+      });
+    });
+
+    it('deletes the bankrec', function (done) {
+      var sql = 'SELECT deleteBankReconciliation(' + bankrec.bankrec_id +
+                ') AS result;';
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result >= 0);
+        done();
+      });
+    });
+
+    it('checks that the bankrec is really gone', function (done) {
+      var sql = 'SELECT COUNT(*) AS result FROM bankrec WHERE bankrec_id = ' +
+                bankrec.bankrec_id + ';';
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result === 0);
+        done();
+      });
+    });
+
+    it('checks that the bankrecitems are gone', function (done) {
+      var sql = 'SELECT COUNT(*) AS result FROM bankrecitem' +
+                ' WHERE bankrecitem_bankrec_id = ' + bankrec.bankrec_id + ';';
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result === 0);
+        done();
+      });
+    });
+
+    it('turns off cash-based tax handling if necessary', function (done) {
+      if (wasCashBasedTax) {
+        done();
+      } else {
+        var sql = "SELECT setMetric('CashBasedTax', 'f') AS result;";
+        datasource.query(sql, creds, function (err, res) {
+          assert.equal(res.rowCount, 1);
+          done();
+        });
+      }
+    });
+
+    it('tries to delete a non-existent bankrec', function (done) {
+      var sql = 'SELECT deleteBankReconciliation(-15) AS result;';
+      datasource.query(sql, creds, function (err, res) {
+        assert.equal(res.rowCount, 1);
+        assert(res.rows[0].result === 0); // no, it doesn't complain
+        done();
+      });
+    });
+
+    it('resets tax_dist_accnt_id to NULL', function (done) {
+      var sql = mqlToSql('UPDATE tax SET tax_dist_accnt_id = NULL' +
+                         ' WHERE tax_id IN (<? literal("idlist") ?>);',
+                         { idlist: badTaxIds.join(', ') });
+      if (badTaxIds.length <= 0) {
+        done();
+      } else {
+        datasource.query(sql, creds, function (err, res) {
+          assert.isNull(err);
+          done();
+        });
+      }
+    });
+
+  });
+}());
index b80e286..45cd47e 100644 (file)
@@ -62,5 +62,3 @@ var _ = require("underscore"),
 
   });
 }());
-
-
index dd8a473..21e4fa3 100644 (file)
@@ -67,7 +67,7 @@ var _ = require("underscore"),
         assert.isNull(err);
         assert.equal(1, res.rowCount, JSON.stringify(res.rows));
         results = JSON.parse(res.rows[1].get);
-        assert.equal(results.data.length, 5);
+        assert.isNumber(results.data.length);
         done();
       });
     });
@@ -93,7 +93,7 @@ var _ = require("underscore"),
         assert.isNull(err);
         assert.equal(1, res.rowCount, JSON.stringify(res.rows));
         results = JSON.parse(res.rows[1].get);
-        assert.equal(results.data.length, 5);
+        assert.isNumber(results.data.length);
         done();
       });
     });
@@ -259,9 +259,9 @@ var _ = require("underscore"),
       datasource.query(sql, creds, function (err, res) {
         var results;
         assert.isNull(err);
-        assert.equal(1, res.rowCount, JSON.stringify(res.rows));
+        assert.isNumber(res.rowCount);
         results = JSON.parse(res.rows[1].get);
-        assert.equal(results.data.length, 20);
+        assert.isNumber(results.data.length);
         done();
       });
     });
@@ -344,7 +344,7 @@ var _ = require("underscore"),
         assert.isNull(err);
         assert.equal(1, res.rowCount, JSON.stringify(res.rows));
         results = JSON.parse(res.rows[1].get);
-        assert.equal(results.data[0].count, 5);
+        assert.isNumber(results.data[0].count);
         done();
       });
     });
index 1124833..e387b7e 100644 (file)
     smoke = require("../../lib/smoke");
 
   describe('Configuration Workspaces', function () {
-    this.timeout(30 * 1000);
+    this.timeout(60 * 1000);
 
     before(function (done) {
       zombieAuth.loadApp(done);
     });
 
     it('should all be accessible', function (done) {
-      this.timeout(80 * 1000);
+      this.timeout(120 * 1000);
       var navigator, workspace,
         list,
         i = -1;
index 09e017d..eb46302 100644 (file)
       zombieAuth.loadApp(appLoaded);
     });
 
-    describe('Test Grid Boxes', function () {
-      it('Test Grid Box Functionality', function () {
+    it('Test Grid Box Functionality', function () {
+      _.each(XV, function (value, key) {
+        var list,
+          kinds = ['SalesOrderList', 'QuoteList', 'InvoiceList', 'ReturnList', 'ProjectList'];
+        // lists with grid boxes; TODO: find candidates automatically
+        if (_.contains(kinds, key)) {
+          describe('Create Workspace for XV.' + key, function () {
+            it('Create a Workspace', function () {
+              list = "XV." + key;
+              smoke.navigateToNewWorkspace(XT.app, list, function (workspaceContainer) {
+                var workspace = workspaceContainer.$.workspace,
+                    getExportButton = function (obj) {
+                      var result = null;
+                      if (_.isObject(obj.$)) {
+                        result = obj.$.exportButton ||
+                                 _.find(obj.$, getExportButton);
+                      }
+                      return result;
+                    };
 
-        _.each(XV, function (value, key) {
-          var list,
-            kinds = ['SalesOrderList', 'QuoteList', 'InvoiceList', 'ReturnList', 'ProjectList'];
-          // lists with grid boxes; TODO: find candidates automatically
-          if (_.contains(kinds, key)) {
-
-            describe('Create Workspace for XV.' + key, function () {
-              it('Create a Workspace', function () {
-                list = "XV." + key;
-                smoke.navigateToNewWorkspace(XT.app, list, function (workspaceContainer) {
-                  var workspace = workspaceContainer.$.workspace;
-                  _.each(workspace.$, function (component) {
-                    if (XV.inheritsFrom(component, 'XV.GridBox')) {
+                _.each(workspace.$, function (component) {
+                  if (XV.inheritsFrom(component, 'XV.GridBox')) {
+                    describe('Checking ' + component.name, function () {
+                      it('checks for the export button', function () {
+                        var exportButton = getExportButton(component);
+                        assert.ok(exportButton);
+                      });
 
-                      describe('Test creating line items for ' + component, function () {
-                        it('Create line items', function () {
-                          var gridBox = component, gridRow,
+                      it('creates line items for ' + component, function () {
+                        var gridBox = component,
+                            exportButton = getExportButton(gridBox),
+                            gridRow,
                             startingRows = gridBox.liveModels().length;
 
-                          gridBox.newItem();
-                          gridRow = gridBox.$.editableGridRow;
-                          // verify that there is an increase in rows
-                          assert.equal(gridBox.liveModels().length, startingRows += 1);
-
-                          // Add a new row using the enter key
-                          gridRow.bubble("onkeyup", {keyCode: 13});
-                          // verify again that a row has been added
-                          assert.equal(gridBox.liveModels().length, startingRows += 1);
-                        });
+                        // fyi: some workspaces prepopulate with dirty data
+                        if (startingRows == 0) {
+                          assert.isTrue(exportButton.disabled,
+                                       'expect export disabled if no data');
+                        } else if (_.every(gridBox.liveModels(), function (m) {
+                                     return m.isReadyClean(); })) {
+                          assert.isFalse(exportButton.disabled,
+                                       'expect export enabled for clean data');
+                        }
+                        gridBox.newItem();
+                        gridRow = gridBox.$.editableGridRow;
+                        assert.equal(gridBox.liveModels().length, startingRows += 1);
+                        assert.isTrue(exportButton.disabled,
+                                       'export disabled for changed data');
 
-                        it('Check export', function () {
-                          var getExportButton = function (obj) {
-                            var result = null;
-                            if (_.isObject(obj.$)) {
-                              result = obj.$.exportButton ||
-                                       _.find(obj.$, getExportButton);
-                            }
-                            return result;
-                          };
-
-                          var gridBox = component,
-                              exportButton = getExportButton(gridBox);
-                          assert.ok(exportButton);
-                          // TODO: need to populate before we can export
-                          // assert.doesNotThrow(exportButton.doTap());
-                          // TODO: find the generated file & check contents
-                        });
+                        // Add a new row using the enter key
+                        gridRow.bubble("onkeyup", {keyCode: 13});
+                        assert.equal(gridBox.liveModels().length, startingRows += 1);
                       });
-                    }
-                  });
+
+                      // TODO: populate, apply, & actually export
+                      // generate some data
+                      // assert.isTrue(exportButton.disabled,
+                      //               'expect export disabled if no data');
+                      // save the data
+                      // assert.isFalse(exportButton.disabled,
+                      //               'expect export disabled if no data');
+                      // assert.doesNotThrow(exportButton.doTap());
+                      // find the generated file & check contents
+                    });
+                  }
                 });
               });
             });
-          }
-        });
+          });
+        }
       });
     });
   });
index a31a886..2ad8ad4 100644 (file)
@@ -16,7 +16,7 @@
     assert = require("chai").assert;
 
   describe('Workspaces', function () {
-    this.timeout(20 * 1000);
+    this.timeout(60 * 1000);
     it('should log in first', function (done) {
       zombieAuth.loadApp(done);
     });
@@ -83,7 +83,7 @@
     var workspaceContainer, workspace, model, id, moduleContainer;
 
     beforeEach(function (done) {
-      this.timeout(10 * 1000);
+      this.timeout(60 * 1000);
 
       smoke.navigateToExistingWorkspace(XT.app, "XV.ClassCodeList", function (_workspaceContainer) {
         workspaceContainer = _workspaceContainer;
       });
     });
     afterEach(function (done) {
-      this.timeout(10 * 1000);
+      this.timeout(60 * 1000);
 
       // maybe one of the tests already released the lock
       if (!model.hasLockKey()) {
index 7f4a308..a63031f 100644 (file)
@@ -17,7 +17,7 @@
     before(function (done) {
       // setup for the date widget
       var initializeDate = function () {
-        K = enyo.kind({kind: XV.Date});
+        K = enyo.kind({kind: XV.DateWidget});
         K = new K();
         done();
       };
index cf880fc..71f410c 100644 (file)
 
       });
       afterEach(function (done) {
-        this.timeout(10 * 1000);
+        this.timeout(30 * 1000);
 
         // restore permissions
         _.extend(XT.session.privileges.attributes, originalPrivileges);
index 8dbc6a8..43406d3 100644 (file)
@@ -2,7 +2,8 @@
   immed:true, eqeqeq:true, forin:true, latedef:true,
   newcap:true, noarg:true, undef:true */
 /*global XT:true, XM:true, XV:true, describe:true, it:true, setTimeout:true,
-  console:true, before:true, after:true, module:true, require:true */
+  console:true, before:true, after:true, module:true, require:true, setInterval:true,
+  clearInterval:true */
 
 (function () {
   "use strict";
@@ -16,7 +17,6 @@
     gridRow,
     gridBox,
     workspace,
-    skipIfSiteCal,
     primeSubmodels = function (done) {
       var submodels = {};
       async.series([
@@ -44,8 +44,9 @@
       });
     };
 
-  describe('Sales Order Workspace', function () {
-    this.timeout(20 * 1000);
+  // TODO: move to sales order spec
+  describe.skip('Sales Order Workspace', function () {
+    this.timeout(30 * 1000);
 
     //
     // We'll want to have TTOYS, BTRUCK1, and WH1 onhand and ready for the test to work.
@@ -56,7 +57,6 @@
           submodels = submods;
           done();
         });
-        if (XT.extensions.manufacturing && XT.session.settings.get("UseSiteCalendar")) {skipIfSiteCal = true; }
       });
     });
 
           assert.equal(gridBox.liveModels().length, 1);
         });
       });
-      it('Supply list should have action to open Item Workbench', function (done) {
-        if (!XT.extensions.inventory) {
-          done();
-          return;
-        }
-        var verify,
-          action = _.find(gridBox.$.supplyList.actions, function (action) {
-            return action.name === "openItemWorkbench";
-          }),
-          prereq = action.prerequisite;
-        gridBox.$.supplyButton.bubble("ontap");
-        gridBox.$.supplyList.select(0);
-
-        gridBox.$.supplyList.value.models[0][prereq](function (hasPriv) {
-          assert.isTrue(hasPriv);
-          if (hasPriv) {
-            gridBox.$.supplyList.actionSelected(null, {action: {method: "openItemWorkbench"}, index: 0});
-
-            setTimeout(function () {
-              assert.equal(XT.app.$.postbooks.getActive().$.workspace.kind, "XV.ItemWorkbenchWorkspace");
-              XT.app.$.postbooks.getActive().doPrevious();
-              assert.equal(XT.app.$.postbooks.getActive().$.workspace.kind, "XV.SalesOrderWorkspace");
-              done();
-            }, 3000);
-          } else {done(); }
-        });
-      });
       it('adding a second line item should not copy the item', function (done) {
         workspace.value.once("change:total", done());
 
         assert.equal(gridBox.liveModels().length, 2);
         assert.notEqual(submodels.itemModel.id, gridRow.$.itemSiteWidget.$.privateItemSiteWidget.$.input.value);
 
-        // The intention was to delete the above line after verifying that the item doesn't copy but ran into 
+        // The intention was to delete the above line after verifying that the item doesn't copy but ran into
         // many issues so just populating with same data and saving it with 2 line items.
         gridRow.$.itemSiteWidget.doValueChange({value: {item: submodels.itemModel, site: submodels.siteModel}});
         gridRow.$.quantityWidget.doValueChange({value: 5});
             });
         */
       });
-      // XXX - skip test if site calendar is enabled -
-      // temporary until second notifyPopup (_nextWorkingDate) is handled in test (TODO).
-
-      //it('changing the Schedule Date updates the line item\'s schedule date', function (done) {
-      (skipIfSiteCal ? it.skip : it)(
-        'changing the Schedule Date updates the line item\'s schedule date', function (done) {
-        var getDowDate = function (dow) {
-            var date = new Date(),
-              currentDow = date.getDay(),
-              distance = dow - currentDow;
-            date.setDate(date.getDate() + distance);
-            return date;
-          },
-          newScheduleDate = getDowDate(0); // Sunday from current week
-
-        var handlePopup = function () {
-          assert.equal(workspace.value.get("scheduleDate"), newScheduleDate);
-          // Confirm to update all line items
-          XT.app.$.postbooks.notifyTap(null, {originator: {name: "notifyYes"}});
-          // And verify that they were all updated with the new date
-          setTimeout(function () {
-            _.each(workspace.value.get("lineItems").models, function (model) {
-              assert.equal(newScheduleDate, model.get("scheduleDate"));
-            });
-            done();
-          }, 3000);
+      it('deleting an item through SalesOrderLineWorkspace should remove it from the line item ' +
+        'list', function (done) {
+        var lineItemBox = workspace.$.salesOrderLineItemBox,
+          model = lineItemBox.value.models[0],
+          startModelLength = lineItemBox.liveModels().length,
+          moduleContainer = XT.app.$.postbooks;
+
+        /** Open the first model's salesOrderLineWorkspace...
+            Copied from gridBox buttonTapped function (expandGridRowButton)
+        */
+        lineItemBox.doChildWorkspace({
+          workspace: lineItemBox.getWorkspace(),
+          collection: lineItemBox.getValue(),
+          index: lineItemBox.getValue().indexOf(model)
+        });
+
+        /** The line item's workspace model has been deleted (DESTROYED_CLEAN).
+            Client is now in SalesOrderWorkspace.
+        */
+        var statusChanged = function () {
+          assert.notEqual(startModelLength, lineItemBox.liveModels().length);
+          done();
         };
 
-        workspace.value.once("change:scheduleDate", handlePopup);
-        workspace.value.set("scheduleDate", newScheduleDate);
+        model.once("status:DESTROYED_CLEAN", statusChanged);
+
+        // Function to keep checking for notifyPopup showing and then tap yes.
+        // This will fire right after the delete below.
+        var notifyPopupInterval = setInterval(function () {
+          if (!moduleContainer.$.notifyPopup.showing) { return; }
+          clearInterval(notifyPopupInterval);
+          moduleContainer.notifyTap(null, {originator: {name: "notifyYes" }});
+        }, 100);
+        // Delete the item in the workspace
+        moduleContainer.getActive().deleteItem();
       });
+
       it('save, then delete order', function (done) {
-        assert.equal(workspace.value.status, XM.Model.READY_NEW);
+        assert.isTrue((workspace.value.status === XM.Model.READY_DIRTY ||
+          workspace.value.status === XM.Model.READY_NEW));
         smoke.saveWorkspace(workspace, function (err, model) {
           assert.isNull(err);
-          // TODO: sloppy
+          // XXX - sloppy
           setTimeout(function () {
             smoke.deleteFromList(XT.app, model, done);
           }, 4000);
index 152e1dc..7f95c00 100644 (file)
@@ -14,7 +14,7 @@ var _ = require("underscore"),
 
   exports.accountBeforeDeleteActions = [{it: 'saves the account id', action: function (data, done) {
     data.deleteData = {
-      accntId: data.model.get("account"),
+      accntId: data.model.get("account").id || data.model.get("account"),
       accountModel: new XM.Account()
     };
     done();
@@ -366,7 +366,7 @@ var _ = require("underscore"),
     // Step 1: load the environment with Zombie
     //
     it('can be loaded with a zombie session', function (done) {
-      this.timeout(40 * 1000);
+      this.timeout(60 * 1000);
       zombieAuth.loadApp({callback: done, verbose: data.verbose,
         loginDataPath: data.loginDataPath});
     });
@@ -383,7 +383,7 @@ var _ = require("underscore"),
     // Step 3: initialize the model to get the ID from the database
     //
     it('can be initialized by fetching an id from the server', function (done) {
-      this.timeout(20 * 1000);
+      this.timeout(60 * 1000);
       init(data, done);
     });
 
@@ -392,13 +392,13 @@ var _ = require("underscore"),
     //
     _.each(data.beforeSetActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(data, done);
       });
     });
 
     it('can have its values set', function (done) {
-      this.timeout(20 * 1000);
+      this.timeout(60 * 1000);
       data.updated = false;
       setModel(data, done);
     });
@@ -406,14 +406,14 @@ var _ = require("underscore"),
     // if this model has comments, set them on the model
     if (data.commentType) {
       it('can have its comments set', function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         setComments(data, done);
       });
     }
 
     _.each(data.beforeSaveActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(data, done);
       });
     });
@@ -423,12 +423,12 @@ var _ = require("underscore"),
     //
     if (!data.skipSave) {
       it('can be saved to the database', function (done) {
-        this.timeout(10 * 1000);
+        this.timeout(60 * 1000);
         save(data, done);
       });
       _.each(data.afterSaveActions || [], function (spec) {
         it(spec.it, function (done) {
-          this.timeout(20 * 1000);
+          this.timeout(60 * 1000);
           spec.action(data, done);
         });
       });
@@ -446,7 +446,7 @@ var _ = require("underscore"),
       // Step 7: save the updated model to the database
       //
       it('can be re-saved to the database', function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         save(data, done);
       });
     }
@@ -456,21 +456,21 @@ var _ = require("underscore"),
     //
     _.each(data.beforeDeleteActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(data, done);
       });
     });
 
     if (!data.skipDelete) {
       it('can be deleted from the database', function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         destroy(data, done);
       });
     }
 
     _.each(data.afterDeleteActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(data, done);
       });
     });
index 8608927..4ede092 100644 (file)
@@ -161,7 +161,9 @@ require:true, __dirname:true, console:true */
             _.each(spec.extensions, function (extension) {
               it("has privilege " + priv + " declared by the " + extension + " extension", function () {
                 assert.isDefined(_.findWhere(XT.session.relevantPrivileges,
-                  {privilege: priv, module: spec.relevantPrivilegeModule || extension}));
+                  {privilege: priv, module: spec.relevantPrivilegeModule || extension}),
+                  "Perhaps you're adding the privilege in a different module and haven't set the " +
+                  "spec.relevantPrivilegeModule attribute to be that module?");
               });
             });
             /*
index df0c588..1662994 100644 (file)
 
     // back up to list
     app.$.postbooks.previous();
+    if (app.$.postbooks.getActive().kind === "XV.WorkspaceContainer") {
+      console.log("Ok, we want to be in the navigator by now");
+      console.log("Model status is", model.getStatusString());
+      console.log("Notify popup showing?", XT.app.$.postbooks.$.notifyPopup.showing);
+      console.log("Notify popup message", XT.app.$.postbooks.$.notifyMessage.getContent());
+    }
     assert.equal(app.$.postbooks.getActive().kind, "XV.Navigator");
 
     // here's the list
 
   exports.updateFirstModel = function (test) {
     it('should allow a trivial update to the first model of ' + test.kind, function (done) {
-      this.timeout(20 * 1000);
+      this.timeout(60 * 1000);
       navigateToExistingWorkspace(XT.app, test.kind, function (workspaceContainer) {
         var updateObj,
           statusChanged,
     var workspaceContainer,
       workspace;
     it('can get to a new workspace', function (done) {
-      this.timeout(10 * 1000);
+      this.timeout(60 * 1000);
       navigateToNewWorkspace(XT.app, spec.listKind, function (_workspaceContainer) {
         workspaceContainer = _workspaceContainer;
         done();
     });
     _.each(spec.beforeSaveUIActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(workspace, done);
       });
     });
     it('can save the workspace', function (done) {
-      this.timeout(20 * 1000);
+      this.timeout(60 * 1000);
       if (spec.captureObject) {
         XG = XG || {};
         XG.capturedId = workspace.value.id;
       }
       saveWorkspace(workspace, done);
     });
+    _.each(spec.afterSaveUIActions || [], function (spec) {
+      it(spec.it, function (done) {
+        this.timeout(60 * 1000);
+        spec.action(workspace, done);
+      });
+    });
     if (spec.captureObject) {
       return;
     }
     it('can delete the item from the list', function (done) {
-      this.timeout(20 * 1000);
+      this.timeout(60 * 1000);
       deleteFromList(XT.app, workspace.value, done);
     });
   };
index c2aa555..26116e3 100755 (executable)
@@ -32,7 +32,7 @@ require:true, __dirname:true, console:true, process:true */
     specFiles = _.filter(fs.readdirSync(path.join(__dirname, "../specs")), function (fileName) {
       // filter out .swp files, etc.
       return path.extname(fileName) === '.js';
-    }),
+    }).sort(),
     specs = _.map(specFiles, function (specFile) {
       var fileExports = require(path.join(__dirname, "../specs", specFile));
       if (!fileExports || !fileExports.spec) {
index a3b3790..579c608 100644 (file)
@@ -2,6 +2,35 @@
 regexp:true, undef:true, strict:true, trailing:true, white:true */
 /*global XT:true, XM:true, XV:true, XZ:true, enyo:true, XG:true */
 
+var _ = require('underscore');
+global.URL = require('url');
+var parse = global.URL.parse;
+var resolve = global.URL.resolve;
+global.URL.parse = function (url) {
+  "use strict";
+  console.log('URL.parse', url);
+  if (_.isObject(url) && _.isString(url.href)) {
+    return parse(url.href);
+  }
+  else {
+    return parse(url);
+  }
+};
+global.URL.resolve = function (from, to) {
+  "use strict";
+  console.log('URL.resolve from', from);
+  console.log('URL.resolve to', to);
+  if (_.isObject(from)) {
+    from = from.href || '/';
+  }
+  if (_.isObject(to)) {
+    to = to.href || '';
+  }
+
+  return resolve(from, to);
+};
+
+
 // global objects
 enyo = {};
 XT = {};
@@ -10,9 +39,11 @@ XM = {};
 XV = {};
 XZ = {}; // xTuple Zombie. Used to help zombie within the context of these tests.
 
+// https://github.com/mikeal/request/issues/418#issuecomment-17149236
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
+
 var assert = require('assert'),
   zombie = require('zombie'),
-  URL = require('url'),
   _ = require('underscore');
 
 
@@ -100,23 +131,15 @@ Simplest possible usage:
       return;
     }
 
-    var parse = URL.parse;
-    URL.parse = function (url) {
-      if (_.isObject(url) && _.isString(url.href)) {
-        return parse(url.href);
-      }
-      else {
-        return parse(url);
-      }
-    };
 
-    zombie.visit(host, {debug: verboseMode}, function (e, browser) {
+    zombie.visit(host, {debug: verboseMode, runScripts: false}, function (e, browser) {
       if (e) {
-        //console.log("Zombie visit error: ", e);
+        console.log("Zombie visit error: ", e);
       }
       //
       // This is the login screen
       //
+      browser.runScripts = true;
       browser
         .fill('id', username)
         .fill('password', password)
diff --git a/test/models/credit_card.js b/test/models/credit_card.js
deleted file mode 100755 (executable)
index b3ac016..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*jshint trailing:true, white:true, indent:2, strict:true, curly:true,
-  immed:true, eqeqeq:true, forin:true, latedef:true,
-  newcap:true, noarg:true, undef:true */
-/*global XT:true, XM:true, XV:true, exports:true, describe:true, it:true, require:true */
-
-(function () {
-  "use strict";
-
-  var crud = require("../lib/crud"),
-    assert = require("chai").assert;
-
-  var data = exports.data = {
-    recordType: "XM.CreditCard",
-    autoTestAttributes: false,
-    createHash: {
-      customer: 95, // TTOYS
-      creditCardType: "V",
-      name: "John Smith",
-      address1: "123 Main Street",
-      city: "Norfolk",
-      state: "VA",
-      zip: "23510",
-      country: "USA",
-      monthExpired: "05",
-      yearExpired: "2010",
-      number: "4111111111111111",
-      sequence: 500
-    },
-    updateHash: {
-      creditCardType: "M",
-      number: "1234123412341234",
-      sequence: 550
-    },
-    afterSaveActions: [{
-      it: "should mask the first 12 digits of the credit card number",
-      action: function (data, next) {
-        assert.equal(data.model.get("sequence"), 500);
-        assert.equal(data.model.get("name"), "John Smith");
-        assert.equal(data.model.get("number"), "************1111");
-        next();
-      }
-    }],
-    beforeDeleteActions: [{
-      it: "should not allow an update to the number or type",
-      action: function (data, next) {
-        assert.equal(data.model.get("sequence"), 550);
-        assert.equal(data.model.get("creditCardType"), "V");
-        assert.equal(data.model.get("number"), "************1111");
-        next();
-      }
-    }],
-    skipDelete: true
-  };
-
-  describe('Credit card crud test', function () {
-    crud.runAllCrud(data);
-  });
-}());
index 0a6659c..3be3de5 100644 (file)
@@ -7,6 +7,8 @@ setTimeout:true, before:true, clearTimeout:true, exports:true, it:true, describe
 (function () {
   "use strict";
 
+  var assert = require("chai").assert;
+
   /**
     @class
     @alias Country
@@ -70,18 +72,44 @@ setTimeout:true, before:true, clearTimeout:true, exports:true, it:true, describe
     updatableField: "name"
   };
   var additionalTests = function () {
-    /**
-      @member -
-      @memberof Country.prototype
-      @description Length of Abbreviation field should not exceed 2, Currency Abbreviation
-      and Currency Number should not exceed 3 and Currency Number value should be an integer
-    */
-    it.skip("Abbreviation length should not exceed 2", function () {
-    });
-    it.skip("Length of Currency Abbreviation should not exceed 3", function () {
-    });
-    it.skip("Currency Number value should be an integer and its length should not" +
-    " exceed 3 ", function () {
+    describe("Country field validation", function () {
+      var countryModel;
+
+      beforeEach(function () {
+        countryModel = new XM.Country();
+        countryModel.initialize(null, {isNew: true});
+      });
+      /**
+        @member -
+        @memberof Country.prototype
+        @description Length of Abbreviation field should be 2, Currency Abbreviation
+        and Currency Number should be 3
+      */
+      it("Abbreviation length should be less than 2", function () {
+        countryModel.set("abbreviation", "A");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
+      it("Length of Currency Abbreviation should not be less than 3", function () {
+        countryModel.set("currencyAbbreviation", "AB");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
+      it("Currency Number length should not be less than 3", function () {
+        countryModel.set("currencyNumber", "AB");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
+
+      it("Abbreviation length should not exceed 2", function () {
+        countryModel.set("abbreviation", "ABC");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
+      it("Length of Currency Abbreviation should not exceed 3", function () {
+        countryModel.set("currencyAbbreviation", "ABCD");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
+      it("Currency Number length should not exceed 3", function () {
+        countryModel.set("currencyNumber", "ABCD");
+        assert.isObject(countryModel.validate(countryModel.attributes));
+      });
     });
   };
   exports.spec = spec;
diff --git a/test/specs/credit_card.js b/test/specs/credit_card.js
deleted file mode 100644 (file)
index 7b01580..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*jshint trailing:true, white:true, indent:2, strict:true, curly:true,
-  immed:true, eqeqeq:true, forin:true, latedef:true,
-  newcap:true, noarg:true, undef:true */
-/*global describe:true, it:true, XT:true, XM:true, XV:true, process:true,
-  module:true, require:true, exports:true */
-
-(function () {
-  "use strict";
-  
-  var crud = require("../lib/crud"),
-    assert = require("chai").assert;
-   /**
-  @class
-  @alias CreditCard
-  @property {String} id
-  @property {String} sequence
-  @property {Customer} Customer
-  @property {Boolean} isActive
-  @property {Name} Name
-  @property {String} Address1
-  @property {String} Address2
-  @property {String} City
-  @property {String} State
-  @property {String} Zip
-  @property {Country} Country
-  @property {Number} Number
-  @property {Date} monthExpired
-  @property {Date} yearExpired
-  @property {Boolean} isDebit
-  @property {String} CreditCardType
-  **/
-  var spec = {
-    skipAll: true,
-    recordType: "XM.CreditCard",
-    enforceUpperKey: false,
-    collectionType: "XM.CreditCardCollection",
-    listKind: "XV.CreditCardList",
-    instanceOf: "XM.Model",
-    attributes: ["id", "uuid", "sequence", "customer", "isActive", "name", "address1", "address2",
-    "city", "state", "zip", "country", "number", "monthExpired", "yearExpired", "isDebit",
-    "creditCardType"],
-    idAttribute: "uuid",
-    /**
-      @member -
-      @memberof CreditCard
-      @description Used in the Sales and billing modules
-    */
-    extensions: ["sales"],
-    /**
-      @member -
-      @memberof CreditCard
-      @description CreditCards are not lockable.
-    */
-    isLockable: false,
-    /**
-    @member -
-    @memberof CreditCard
-    @description The Credit Card collection is cached.
-    */
-    cacheName: null,
-    /**
-      @member -
-      @memberof CreditCard
-      @description CreditCards can be created and updated by users with the "ProcessCreditCards"
-      privilege but cannot be deleted
-    */
-    privileges: {
-      createUpdate: "ProcessCreditCards",
-      read: "ProcessCreditCards"     
-    },
-    createHash : {
-      customer: 95, // TTOYS
-      creditCardType: "V",
-      name: "John Smith",
-      address1: "123 Main Street",
-      city: "Norfolk",
-      state: "VA",
-      zip: "23510",
-      country: "USA",
-      monthExpired: "05",
-      yearExpired: "2010",
-      number: "4111111111111111",
-      sequence: 500
-    },
-    updateHash: {
-      creditCardType: "M",
-      number: "1234123412341234",
-      sequence: 550
-    },
-    /**
-      @member -
-      @memberof CreditCard
-      @description First 12 digits of the credit card number should be masked
-    */
-    afterSaveActions: [{
-      it: "should mask the first 12 digits of the credit card number",
-      action: function (data, next) {
-        assert.equal(data.model.get("sequence"), 500);
-        assert.equal(data.model.get("name"), "John Smith");
-        assert.equal(data.model.get("number"), "************1111");
-        next();
-      }
-    }],
-    /**
-      @member -
-      @memberof CreditCard
-      @description User should not be allowed to update the number/type of the Credit Card
-    */
-    beforeDeleteActions: [{
-      it: "should not allow an update to the number or type",
-      action: function (data, next) {
-        assert.equal(data.model.get("sequence"), 550);
-        assert.equal(data.model.get("creditCardType"), "V");
-        assert.equal(data.model.get("number"), "************1111");
-        next();
-      }
-    }],
-    skipDelete: true
-    
-  };
-  exports.spec = spec;
-}());
index 3651272..f710558 100644 (file)
@@ -58,7 +58,6 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
     @property {CustomerAccount} CRMAccount
     */
   var spec = {
-    skipAll: true,
     recordType: "XM.Customer",
     collectionType: "XM.CustomerListItemCollection",
     /**
@@ -139,6 +138,7 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
           };
         creditCardModel.on("change:uuid", setCreditCard);
         creditCardModel.initialize(null, {isNew: true});
+        assert.isTrue(creditCardModel.canEdit("creditCardType"));
       }
     }],
     afterSaveActions: [{
@@ -147,6 +147,13 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
         assert.equal(data.model.get("creditCards").models[0].get("number"), "************1111");
         next();
       }
+    }, {
+      it: "should not allow an edit to the saved credit card",
+      action: function (data, next) {
+        var creditCardModel = data.model.get("creditCards").models[0];
+        assert.isFalse(creditCardModel.canEdit("creditCardType"));
+        next();
+      }
     }],
     beforeDeleteActions: crud.accountBeforeDeleteActions,
     afterDeleteActions: crud.accountAfterDeleteActions
@@ -269,7 +276,7 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
     @description Tax Registrations panel should exist to attach existing/new Tax Registrations
     to the Customer
     @property {String} id ID attribute
-    @property {Customer} Customer 
+    @property {Customer} Customer
     @property {TaxAuthority} TaxAuthority
     @property {String} Number
     @property {TaxZone} TaxZone
@@ -287,7 +294,7 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
         "'number', 'taxZone', 'effective', 'expires', 'notes'", function () {
       });
        /**
-      @member 
+      @member
       @memberof CustomerTaxRegistration
       @description Users can create, update, and delete Tax Registrations if they have the
         MaintainTaxRegistrations privilege, and they can read Tax Registrations if they have
index 509d231..ba4e2db 100644 (file)
@@ -122,6 +122,16 @@ setTimeout:true, before:true, clearTimeout:true, exports:true, it:true, describe
         incidentModel.set("assignedTo", new XM.UserAccountRelation());
         assert.equal(incidentModel.get("status"), XM.Incident.ASSIGNED);
       });
+      it("Incident status does not revert to assigned from closed when user is assigned to it", function () {
+        incidentModel.set("status", XM.Incident.CLOSED);
+        incidentModel.set("assignedTo", new XM.UserAccountRelation());
+        assert.equal(incidentModel.get("status"), XM.Incident.CLOSED);
+      });
+      it("Incident status does not revert to assigned from resolved when user is assigned to it", function () {
+        incidentModel.set("status", XM.Incident.RESOLVED);
+        incidentModel.set("assignedTo", new XM.UserAccountRelation());
+        assert.equal(incidentModel.get("status"), XM.Incident.RESOLVED);
+      });
     });
     /**
     @member Privileges
index f0c443f..e674090 100644 (file)
@@ -183,8 +183,8 @@ TODO deferred to later sprint:
         var gridRow;
 
         workspace.value.on("change:total", done);
-        workspace.$.invoiceLineItemBox.newItem();
-        gridRow = workspace.$.invoiceLineItemBox.$.editableGridRow;
+        workspace.$.lineItemBox.newItem();
+        gridRow = workspace.$.lineItemBox.$.editableGridRow;
         // TODO
         //gridRow.$.itemSiteWidget.doValueChange({value: {item: submodels.itemModel,
           //site: submodels.siteModel}});
@@ -1211,10 +1211,10 @@ TODO deferred to later sprint:
 
         enyo.platform.touch = true;
         workspace = new XV.InvoiceWorkspace();
-        assert.equal(workspace.$.invoiceLineItemBox.kind, "XV.InvoiceLineItemBox");
+        assert.equal(workspace.$.lineItemBox.kind, "XV.InvoiceLineItemBox");
         enyo.platform.touch = false;
         workspace = new XV.InvoiceWorkspace();
-        assert.equal(workspace.$.invoiceLineItemBox.kind, "XV.InvoiceLineItemGridBox");
+        assert.equal(workspace.$.lineItemBox.kind, "XV.InvoiceLineItemGridBox");
       });
       /**
         @member Navigation
@@ -1319,123 +1319,8 @@ TODO deferred to later sprint:
   exports.spec = spec;
   exports.additionalTests = additionalTests;
 
-
-
 /*
 
-***** CHANGES MADE BY INVENTORY EXTENSION ******
-
-* XM.InvoiceLine will include:
-  > Boolean "updateInventory"
-* The updateInventory attribute is readOnly unless all the following are true
-  > The invoice is unposted.
-  > A valid item is selected.
-  > The item and site do not resolve to an item site that is job cost
-  > There is no associated salesOrderLine (attr added by sales extension)
-
-* XM.InvoiceListItem will include:
-  > String "shipDate"
-  > String "shipToName"
-* XM.InvoiceListItem will extend the post function to include inventory information
-  * For each line item where "updateInventory" is true, issue materials to the invoice
-  * Capture distribution detail (trace and location) where applicable
-#HINT: This will likely require creating an alternate dispatchable "post" function that
-  accepts an invoice id _and_ inventory data.
-
-* XM.Invoice will include:
-  > Date "shipDate" default today
-  > CustomerShiptoRelation "shipto"
-  > String "shiptoName"
-  > String "shiptoAddress1"
-  > String "shiptoAddress2"
-  > String "shiptoAddress3"
-  > String "shiptoCity"
-  > String "shiptoState"
-  > String "shiptoPostalCode"
-  > String "shiptoCountry"
-  > String "shiptoPhone"
-  > ShipCharge "shipCharge"
-  > ShipZone "shipZone"
-  > String "incoterms" // HINT: This is the "invchead_fob" field
-  > String "shipVia" (The preferred Ship Via method for the Customer will appear in the field. You may change the Ship Via using the list.)
-  > Money "freight" required, default 0
-* When the customer changes will copy the following attributes from the customer model:
-  > shipCharge
-  > shipto (If a default customer shipto exists)
-  > The following fields will be set to read only if the customer does not allow free
-  form shipnto:
-    - shiptoName
-    - shiptoAddress1
-    - shiptoAddress2
-    - shiptoAddress3
-    - shiptoCity
-    - shiptoState
-    - shiptoPostalCode
-    - shiptoCountry
-    - shiptoPhone
-* The inventory extension adds a function to XM.Invoice "copyBilltoToShipto" that
-does the following
-  > Clears the shipto
-  > Copies billto name, address fields and phone number to shipto equivilants.
-  > Sets the invoice tax zone to the customer tax zone.
-* When an invoice is loaded where "isPosted" is true, then the following attributes
-will be made read only:
-  > lineItems
-  > number
-  > invoiceDate
-  > terms
-  > salesrep
-  > commission
-  > taxZone
-  > shipCharges
-  > project
-  > freight
-  > shipZone
-  > saleType
-
-* If the shipto changes to a value, the following fields should be set based on information
-from the shipto:
-  - shiptoName (= customer.shipto.name)
-  - shiptoAddress1
-  - shiptoAddress2
-  - shiptoAddress3
-  - shiptoCity
-  - shiptoState
-  - shiptoPostalCode
-  - shiptoCountry (< ^ should be populated by the default customer.shipto.address).
-  - shiptoPhone
-  - salesRep
-  - commission
-  - taxZone
-  - shipCharge
-  - shipZone
-* if the shipto is cleared these fields should be unset
-  - shiptoName
-  - shiptoAddress1
-  - shiptoAddress2
-  - shiptoAddress3
-  - shiptoCity
-  - shiptoState
-  - shiptoPostalCode
-  - shiptoCountry
-  - shiptoPhone
-* If any of the above listed shipto attributes are manually altered, the shipto is unset.
-
-* Freight should be read only and zero when the "isCustomerPay" property is false on the ship
-charge associated with the invoice.
-
-* totalTax should be recalculated when freight changes.
-
-* Add the following to the invoice workspace:
-  > When the customer is changed on the XV.InvoiceWorkspace model:
-    - customer should be set on shipto relation so that it will search on and select from that
-    customer's shipto addresses.
-    - The bill to address should be supplimented with a "Shipto" button that when clicked runs
-    the copyToShipto function ()
-    - The copy ship to button should be disabled if the customer does not allow free-form shiptos.
-  > The shipto addresses available when searching addresses sholud filter on the addresses
-  associated with the customer's account record by default.
-
 ***** CHANGES MADE BY MANUFACTURING EXTENSION ******
 
 * A nested only model should be created according to convention for many-to-many document
index 68565d4..e81e613 100644 (file)
@@ -136,8 +136,8 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
           primeSubmodels = require("./sales_order").primeSubmodels;
 
         primeSubmodels(function (submodels) {
-          workspace.$.returnLineItemBox.newItem();
-          gridRow = workspace.$.returnLineItemBox.$.editableGridRow;
+          workspace.$.lineItemBox.newItem();
+          gridRow = workspace.$.lineItemBox.$.editableGridRow;
           gridRow.$.itemSiteWidget.doValueChange({value: {item: submodels.itemModel,
             site: submodels.siteModel}});
           gridRow.$.quantityWidget.doValueChange({value: 5});
@@ -1038,10 +1038,10 @@ it:true, describe:true, beforeEach:true, before:true, enyo:true */
 
         enyo.platform.touch = true;
         workspace = new XV.ReturnWorkspace();
-        assert.equal(workspace.$.returnLineItemBox.kind, "XV.ReturnLineItemBox");
+        assert.equal(workspace.$.lineItemBox.kind, "XV.ReturnLineItemBox");
         enyo.platform.touch = false;
         workspace = new XV.ReturnWorkspace();
-        assert.equal(workspace.$.returnLineItemBox.kind, "XV.ReturnLineItemGridBox");
+        assert.equal(workspace.$.lineItemBox.kind, "XV.ReturnLineItemGridBox");
       });
       /**
         @member -
index cfcdf28..bc3c845 100644 (file)
@@ -4,28 +4,75 @@
 /*global describe:true, it:true, XT:true, XM:true, XV:true, process:true,
   module:true, require:true, exports:true */
 
-  (function () {
+(function () {
   "use strict";
 
+  var assert = require("chai").assert,
+    smoke = require("../lib/smoke");
+
   /**
   Sites typically describe physical production and storage facilities. work centers, item sites, and site locations belong to sites.
   @class
   @alias Site
   **/
-  exports.spec = {
-    skipAll: true,
-    // XXX very awkward
-    recordType: "XM.Site"
+  var spec = {
+    // smoke is ran in the inventory site spec
+    skipSmoke: true,
+    recordType: "XM.Site",
+    collectionType: "XM.SiteCollection",
+    /**
+      @member -
+      @memberof Sites.prototype
+      @description The site collection is cached.
+    */
+    cacheName: "XM.sites",
+    listKind: "XV.SiteList",
+    instanceOf: "XM.Document",
+    extensions: [],
+    /**
+      @member -
+      @memberof Sites.prototype
+      @description Sites are lockable.
+    */
+    isLockable: true,
+    /**
+      @member -
+      @memberof Sites.prototype
+      @description The ID attribute is "code", which will not be automatically uppercased.
+    */
+    idAttribute: "code",
+    enforceUpperKey: false,
+    attributes: ["code", "address", "code", "comments", "contact", "description", "incoterms",
+      "isActive", "siteType", "taxZone"],
+    privileges: {
+      createUpdateDelete: "MaintainWarehouses",
+      view: true
+    },
+    createHash: {
+      isActive: true,
+      code: "NewSite" + Math.random(),
+      siteType: {name: "MFG"}
+    },
+    updatableField: "description"
   };
+
   var additionalTests = function () {
     /**
       @member Setup
       @memberof Site.prototype
-      @description Multiple Item Sites should not be allowed on Postbooks
+      @description Multiple Sites should not be allowed on Postbooks
     */
-    it.skip("Multiple Item Sites should not be allowed on Postbooks", function () {
+    it("Multiple Sites should not be allowed on Postbooks", function (done) {
+      if (!XT.extensions.inventory) {
+        assert.equal(XM.sites.length, 1);
+        smoke.navigateToList(XT.app, "XV.SiteList");
+        assert.isTrue(XT.app.$.postbooks.getActive().$.newButton.disabled);
+        return done();
+      }
+      done();
     });
-};
+  };
 
+  exports.spec = spec;
   exports.additionalTests = additionalTests;
-}());
\ No newline at end of file
+}());