Merge pull request #1843 from xtuple/4_6_x
authorSteve Hackbarth <stephenhackbarth@gmail.com>
Wed, 17 Sep 2014 14:39:43 +0000 (10:39 -0400)
committerSteve Hackbarth <stephenhackbarth@gmail.com>
Wed, 17 Sep 2014 14:39:43 +0000 (10:39 -0400)
4 6 x

160 files changed:
.gitignore
.travis.yml
README.md
RELEASE.md [deleted file]
enyo-client/application/source/ext/session.js
enyo-client/application/source/models/address.js
enyo-client/application/source/models/site.js
enyo-client/application/source/preliminaries.js
enyo-client/application/source/views/list.js
enyo-client/application/source/views/module_container.js
enyo-client/application/source/views/workspace.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/source/update_version.sql
enyo-client/database/source/xt/views/itemsiteinfo.sql
enyo-client/extensions/source/billing/client/core.js
enyo-client/extensions/source/billing/database/source/xt/tables/rptdef.sql
enyo-client/extensions/source/crm/client/core.js
enyo-client/extensions/source/oauth2/client/core.js
enyo-client/extensions/source/oauth2/client/en/strings.js
enyo-client/extensions/source/project/client/core.js
enyo-client/extensions/source/purchasing/client/core.js
enyo-client/extensions/source/sales/client/core.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/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/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/iteminventoryuominuse.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/relocateinventory.sql
foundation-database/public/functions/setnextchecknumber.sql
foundation-database/public/functions/sufficientinventorytoshipitem.sql
foundation-database/public/functions/thawitemsite.sql
foundation-database/public/functions/updatestdcost.sql
foundation-database/public/functions/woinvavail.sql
foundation-database/public/functions/woinvavailmatl.sql
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/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/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/mrpDetail-detail.mql
foundation-database/public/tables/metasql/opensalesorders-detail.mql
foundation-database/public/tables/metasql/pendingAvailability-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/metric.sql
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/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/itemsite.sql
foundation-database/public/trigger_functions/location.sql
foundation-database/public/views/saleshistory.sql
foundation-database/public/views/saleshistorymisc.sql
lib/backbone-x/source/package.js
lib/backbone-x/source/router.js [new file with mode: 0644]
lib/enyo-x/source/app.js
lib/enyo-x/source/core.js
lib/enyo-x/source/less/screen.less
lib/enyo-x/source/stylesheets/screen.css
lib/enyo-x/source/views/grid_box.js
lib/enyo-x/source/views/list.js
lib/enyo-x/source/views/module_container.js
lib/enyo-x/source/views/workspace.js
lib/enyo-x/source/widgets/number.js
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]
node-datasource/main.js
node-datasource/routes/auth.js
node-datasource/routes/generate_oauth_key.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/explode_manifest.js
scripts/install_xtuple.sh
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/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/extensions/all/configure.js
test/extensions/all/workspace.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/zombie_auth.js
test/specs/country.js
test/specs/site.js

index 1892508..76887af 100644 (file)
@@ -1,3 +1,4 @@
+*.log
 *.DS_Store
 *.sw*
 *~
index 7d0d3a4..10dcc2b 100644 (file)
@@ -1,6 +1,6 @@
 language: node_js
 node_js:
-  - "0.8"
+  - "0.10"
 
 install:
   - "bash scripts/install_xtuple.sh -ipn"
index cce4569..ed58ba9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ 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.
 
@@ -61,7 +61,8 @@ 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
   * [Building an Extension Tutorial](https://github.com/xtuple/xtuple-extensions/blob/master/docs/TUTORIAL.md)
diff --git a/RELEASE.md b/RELEASE.md
deleted file mode 100644 (file)
index e7039d6..0000000
+++ /dev/null
@@ -1,2102 +0,0 @@
-4.6.0-beta (2014/07/21)
-=======================
-
-Features and bugfixes
----------------------
-
-- Fixed
-  issue #[18401](http://www.xtuple.org/xtincident/view/bugs/18401)
-  _Relation autocompleter menu gets in the way_
-- Fixed
-  issue #[18409](http://www.xtuple.org/xtincident/view/bugs/18409)
-  _blank screen after login, selecting DB_
-- 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)
-  _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 #[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 #[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 #[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_
-- Fixed
-  issue #[22355](http://www.xtuple.org/xtincident/view/bugs/22355)
-  _Toolbar height changed_
-- 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_
-
-
-
-4.5.2 (2014/07/15)
-==================
-
-Features and bugfixes
----------------------
-- Fixed
-  issue #[23636](http://www.xtuple.org/xtincident/view/bugs/23636) 
-  _Error when running Inventory Availability_ 
-- Fixed 
-  issue #[23714](http://www.xtuple.org/xtincident/view/bugs/23714) 
-  _*Quantity 'At Shipping' gets doubled on selecting 'Issue All' or 'Issue Line' multiple times_ 
-- Fixed 
-  issue #[23979](http://www.xtuple.org/xtincident/view/bugs/23979) 
-  _*Unable to build Mobile Web client on empty databases_ 
-- Fixed 
-  issue #[24098](http://www.xtuple.org/xtincident/view/bugs/24098) 
-  _Icons only displaying when debugging = true_ 
-
-
-4.5.1 (2014/06/25)
-==================
-
-Features and bugfixes
----------------------
-- Fixed 
-  issue #[21772](http://www.xtuple.org/xtincident/view/bugs/21772) 
-  _*Error message is displayed in JS console on selecting to open a configure screen_ 
-- Implemented 
-  issue #[22128](http://www.xtuple.org/xtincident/view/bugs/22128) 
-  _Support filters for dashboards._ 
-- Fixed 
-  issue #[22218](http://www.xtuple.org/xtincident/view/bugs/22218) 
-  _Add support to print and email Sales Order acknowledgements_ 
-- Fixed 
-  issue #[22926](http://www.xtuple.org/xtincident/view/bugs/22926) 
-  _*'Backflush' option is available in the Post production screen for work orders with materials issued_ 
-- Implemented 
-  issue #[22996](http://www.xtuple.org/xtincident/view/bugs/22996) 
-  _signature capture_ 
-- Fixed 
-  issue #[23288](http://www.xtuple.org/xtincident/view/bugs/23288) 
-  _Can not open item work bench from Sales Order_ 
-- Implemented 
-  issue #[23796](http://www.xtuple.org/xtincident/view/bugs/23796) 
-  _Export grid list to csv_ 
-- Implemented 
-  issue #[23852](http://www.xtuple.org/xtincident/view/bugs/23852) 
-  _inventory component of invoice_ 
-- Implemented 
-  issue #[23853](http://www.xtuple.org/xtincident/view/bugs/23853) 
-  _refactor xv.input and xv.inputwidget_ 
-- Fixed 
-  issue #[23860](http://www.xtuple.org/xtincident/view/bugs/23860) 
-  _Handle "no data" case from dashboard filter_ 
-- Fixed 
-  issue #[23867](http://www.xtuple.org/xtincident/view/bugs/23867) 
-  _Add support to XT.Data for x.y.naturalKeyOfY queries_ 
-- Fixed 
-  issue #[23868](http://www.xtuple.org/xtincident/view/bugs/23868) 
-  _*Unable to edit sale order line item after opening item site from line item screen_ 
-- Fixed 
-  issue #[23876](http://www.xtuple.org/xtincident/view/bugs/23876) 
-  _update xwd and xtmfg pkghead_ 
-- Implemented 
-  issue #[23894](http://www.xtuple.org/xtincident/view/bugs/23894) 
-  _Support install of third-party extensions using npm_ 
-- Implemented 
-  issue #[23965](http://www.xtuple.org/xtincident/view/bugs/23965) 
-  _dashboards-lite_ 
-
-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
----------------------
-- Implemented 
-  issue #[23243](http://www.xtuple.org/xtincident/view/bugs/23243) 
-  _unified build: bring in xwd_ 
-- Fixed 
-  issue #[23279](http://www.xtuple.org/xtincident/view/bugs/23279) 
-  _Can't open order on issue to shipping screen_ 
-- Fixed 
-  issue #[23411](http://www.xtuple.org/xtincident/view/bugs/23411) 
-  _Need a way to set Base Currency_ 
-- Fixed 
-  issue #[23559](http://www.xtuple.org/xtincident/view/bugs/23559) 
-  _Syntax error on Sales Orders_ 
-- Fixed 
-  issue #[23588](http://www.xtuple.org/xtincident/view/bugs/23588) 
-  _Item on Sales Order copies irrelevantly_ 
-- Fixed 
-  issue #[23602](http://www.xtuple.org/xtincident/view/bugs/23602) 
-  _Rescheduling Sales Order does not reschedule all lines_ 
-- Fixed 
-  issue #[23607](http://www.xtuple.org/xtincident/view/bugs/23607) 
-  _Description cut off on item site widget_ 
-- Fixed 
-  issue #[23649](http://www.xtuple.org/xtincident/view/bugs/23649) 
-  _Filters on Work Orders do not work_ 
-- Fixed 
-  issue #[23760](http://www.xtuple.org/xtincident/view/bugs/23760) 
-  _error in itemsite list_ 
-
-4.4.1 (2014/05/09)
-==================
-
-Features and bugfixes
----------------------
-- Fixed 
-  issue #[21728](http://www.xtuple.org/xtincident/view/bugs/21728) 
-  _Worksheet (Timesheet) sets rate to 0 on Expense line when Billable unchecked_ 
-- Fixed 
-  issue #[21973](http://www.xtuple.org/xtincident/view/bugs/21973) 
-  _Web client does not work on IE 11_ 
-- Fixed 
-  issue #[23111](http://www.xtuple.org/xtincident/view/bugs/23111) 
-  _Time Expense settings on tasks missing_ 
-- Implemented 
-  issue #[23165](http://www.xtuple.org/xtincident/view/bugs/23165) 
-  _Apply XT.Data buildClause refactor to three implementations_ 
-- Fixed 
-  issue #[23234](http://www.xtuple.org/xtincident/view/bugs/23234) 
-  _Can not enter work sheets without view items privilege_ 
-- Implemented 
-  issue #[23241](http://www.xtuple.org/xtincident/view/bugs/23241) 
-  _Unified build: get data to match in commercial databases_ 
-- Implemented 
-  issue #[23242](http://www.xtuple.org/xtincident/view/bugs/23242) 
-  _unified build: build reports, uiforms, metasql, etc._ 
-- Fixed 
-  issue #[23250](http://www.xtuple.org/xtincident/view/bugs/23250) 
-  _Can not enter a worksheet without unit privileges_ 
-- Fixed 
-  issue #[23323](http://www.xtuple.org/xtincident/view/bugs/23323) 
-  _Errors on search_ 
-- Implemented 
-  issue #[23340](http://www.xtuple.org/xtincident/view/bugs/23340) 
-  _Unified build: move in reports_ 
-- Implemented 
-  issue #[23357](http://www.xtuple.org/xtincident/view/bugs/23357) 
-  _unified build: standard and mfg dbscripts need not be frozen_ 
-- Implemented 
-  issue #[23359](http://www.xtuple.org/xtincident/view/bugs/23359) 
-  _production windows vagrant dry run_ 
-- Fixed 
-  issue #[23370](http://www.xtuple.org/xtincident/view/bugs/23370) 
-  _Can not open documents after "Apply" clicked_ 
-- Fixed 
-  issue #[23402](http://www.xtuple.org/xtincident/view/bugs/23402) 
-  _Cannot create some New things in Empty Database_ 
-- Fixed 
-  issue #[23406](http://www.xtuple.org/xtincident/view/bugs/23406) 
-  _various work order bugs_ 
-- Fixed 
-  issue #[23414](http://www.xtuple.org/xtincident/view/bugs/23414) 
-  _Installing Inventory throws error_ 
-- Fixed 
-  issue #[23560](http://www.xtuple.org/xtincident/view/bugs/23560) 
-  _Sales Order Line items do not default to header site_ 
-- Fixed 
-  issue #[23597](http://www.xtuple.org/xtincident/view/bugs/23597) 
-  _Lazy load does not work on Inventory Availability_ 
-
-
-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 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 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 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 a0e9ba6..f74658d 100644 (file)
@@ -641,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}
           ]}
         ]}
       ]}
@@ -2785,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"}
       ]}
     ]
   });
@@ -3345,5 +3343,4 @@ strict: false*/
   XV.registerModelWorkspace("XM.UserAccountRoleRelation", "XV.UserAccountRoleWorkspace");
   XV.registerModelWorkspace("XM.UserAccountRoleListItem", "XV.UserAccountRoleWorkspace");
 
-
 }());
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 6458648..a23ed94 100644 (file)
@@ -1 +1 @@
-UPDATE pkghead SET pkghead_version = '4.6.0' WHERE pkghead_name = 'xt';
+UPDATE pkghead SET pkghead_version = '4.7.0Beta' WHERE pkghead_name = 'xt';
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 ecd07aa..938c9d3 100644 (file)
@@ -1,4 +1,4 @@
-select xt.add_report_definition('XM.Invoice', 0, $${
+select xt.add_report_definition('XM.Invoice', 0, $${
   "settings": {
     "detailAttribute": "lineItems",
     "defaultFontSize": 12,
@@ -151,12 +151,31 @@ select xt.add_report_definition('XM.Invoice', 0, $${
     },
     {"element": "bandLine", "size": 2},
     {
+      "element": "band",
       "definition": [
-        {"attr": "subtotal", "label": true},
-        {"attr": "taxTotal", "label": true},
-        {"attr": "total", "label": true}
+        {"text": "_subtotal", "label": true, "width": 70, "align": "left"},
+        {"attr": "subtotal", "width": 100, "align": "right"}
       ],
-      "options": {"width": 525, "align": "right"}
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "element": "band",
+      "definition": [
+        {"text": "_taxTotal", "label": true, "width": 70, "align": "left"},
+        {"attr": "taxTotal", "width": 100, "align": "right"}
+      ],
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "element": "band",
+      "definition": [
+        {"text": "_total", "label": true, "width": 70, "align": "left"},
+        {"attr": "total", "width": 100, "align": "right"}
+      ],
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "definition": []
     }
   ],
   "pageFooterElements": [
index 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 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..fc5d4e3 100644 (file)
@@ -17,9 +17,9 @@ 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. Note that this process can take up " +
+      "to a minute. Please wait until the key is downloaded.",
     "_logoURL": "Logo URL",
     "_maintainOauth2clients": "Maintain OAUTH2 Clients",
     "_oauth2": "OAUTH2",
index 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 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 a4a67c4..dcda6af 100644 (file)
@@ -7,6 +7,7 @@
   "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",
     "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/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 78a7ba9..a076ade 100644 (file)
@@ -41002,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;
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 3ae61d0..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,13 +21,12 @@ 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
@@ -42,18 +39,7 @@ BEGIN
   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;
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..c9d7759 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);
@@ -242,8 +252,10 @@ BEGIN
     IF (_r.quitem_createorder) THEN
 
       IF (_r.item_type IN ('M')) THEN
-        SELECT createWo( CAST(_r.quhead_number AS INTEGER), supply.itemsite_id, 1, (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
-                         _r.itemsite_leadtime, _r.quitem_scheddate, _r.quitem_memo, 'S', _soitemid, _r.quhead_prj_id ) INTO _orderId
+        SELECT createWo( CAST(_soNum AS INTEGER), supply.itemsite_id, 1,
+                         (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
+                         _r.itemsite_leadtime, _r.quitem_scheddate, _r.quitem_memo,
+                         'S', _soitemid, _r.quhead_prj_id ) INTO _orderId
         FROM itemsite sold, itemsite supply
         WHERE ((sold.itemsite_item_id=supply.itemsite_item_id)
          AND (supply.itemsite_warehous_id=_r.quitem_order_warehous_id)
@@ -258,7 +270,8 @@ BEGIN
            AND  (charass_target_id=_r.quitem_id));
 
       ELSIF ( (_r.item_type IN ('P', 'O')) AND (_r.itemsite_createsopr) ) THEN
-        SELECT createPr( CAST(_r.quhead_number AS INTEGER), _r.quitem_itemsite_id, (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
+        SELECT createPr( CAST(_soNum AS INTEGER), _r.quitem_itemsite_id,
+                         (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
                          _r.quitem_scheddate, '', 'S', _soitemid ) INTO _orderId;
         _orderType := 'R';
         UPDATE pr SET pr_prj_id=_r.quhead_prj_id WHERE pr_id=_orderId;
index 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 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 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 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;
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 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 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/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/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 6214403..b8b5bf4 100644 (file)
@@ -29,6 +29,14 @@ 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,
+         CASE WHEN (coitem_price = 0.0) THEN 0.0
+              ELSE ROUND(coitem_qtyord * coitem_qty_invuomratio * (coitem_price - coitem_unitcost) / coitem_price_invuomratio,2)
+         END AS margin,
+         CASE WHEN (coitem_price = 0.0) THEN 0.0
+              ELSE ((coitem_price - coitem_unitcost) / coitem_price)
+         END AS marginpercent,
          curr_abbr AS currAbbr,
 -- TODO - not needed, remove? (very slow)
 --         CASE WHEN (qtyAvailable(itemsite_id, coitem_scheddate) < 0.0) THEN 'error'
@@ -43,7 +51,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 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 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 ffcf3ce..4edd402 100644 (file)
@@ -105,8 +105,23 @@ WHERE (true)
 <? if exists("id") ?>
   AND (prj_id=<? value("id") ?>)
 <? endif ?>
-<? literal("charClause") ?>
-<? if exists("prjtype_id") ?>
-   AND (prjtype_id = <? value("prjtype_id") ?>)
+<? 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 abd4a32..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,
@@ -123,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 9e39884..21c8615 100644 (file)
@@ -1 +1,4 @@
-SELECT setMetric('ServerVersion', '4.6.0');
+-- Proof of concept
+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');
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 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 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 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 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 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 ffbd2a8..a2371b6 100644 (file)
@@ -56,6 +56,9 @@
 @defaultPanelWidth: 320px;
 @toolbarHeight: 55px;
 @searchLength: 185px;
+// popups
+@maxMessageHeight: 500px;
+@maxMessageWidth: 500px;
 
 // libs
 @import "../../lib/font-awesome/less/font-awesome.less";
@@ -196,13 +199,16 @@ a, .hyperlink {
 */
 .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;
index 62aa1aa..f123de5 100755 (executable)
@@ -1628,13 +1628,15 @@ a,
 */
 .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;
   border: none;
 }
 /**
-  Styles relating to Lists
-*/
-.xv-list-header {
-  background-color: #d8d8d8;
-  color: #fdfdfd;
-  font-size: .6em;
-  font-weight: bold;
-  text-transform: uppercase;
-  padding-top: 4px;
-  padding-bottom: 4px;
-  border-bottom: 1px solid #aaaaaa;
+ * Default ListItem styles when using a ModelDecorator.
+ */
+.xv-list .xv-model-decorator > .xv-list-item .xv-table {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
 }
-.xv-list-header .xv-list-column.last {
-  border-right: none;
+.xv-list .xv-model-decorator > .xv-list-item .xv-table .xv-cell {
+  display: table-cell;
 }
-.xv-list-header .xv-list-column.name-column,
-.xv-list-header .xv-list-column.first,
-.xv-list-header .xv-list-column.second,
-.xv-list-header .xv-list-column.third,
-.xv-list-header .xv-list-column.short,
-.xv-list-header .xv-list-column.small,
-.xv-list-header .xv-list-column.medium,
-.xv-list-header .xv-list-column.descr {
-  padding-left: 7px;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr {
+  /**
+        * Default styling for a model's id (as designated by 'idAttribute')
+        */
 }
-/* List */
-.xv-list-column.line-number {
-  width: 30px;
-  text-align: right;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attribute-id {
+  color: #357ec7;
+  font-weight: bold;
+  cursor: pointer;
 }
-.xv-list-column.name-column {
-  width: 200px;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attribute-name {
+  font-weight: bold;
 }
-.xv-list-column.right-column {
-  width: 100px;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-number {
   text-align: right;
 }
-.xv-list-column.short {
-  width: 100px;
-}
-.xv-list-column.small {
-  width: 125px;
-}
-.xv-list-column.medium {
-  width: 150px;
-}
-.xv-list-column.first {
-  width: 300px;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-money {
+  text-align: right;
 }
-.xv-list-column.second {
-  width: 200px;
+.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-date {
+  text-align: right;
 }
-.xv-list-column.third {
-  width: 100px;
+.xv-list .xv-model-decorator > .xv-list-item.item-selected .xv-list-attr {
+  color: white;
 }
-.xv-list-column.money,
-.xv-list-column.quantity {
-  width: 75px;
-  text-align: right;
+.xv-list .xv-model-decorator > .xv-list-item.item-selected .xv-list-attr.xm-attribute-id {
+  color: #ff6529;
 }
-.xv-list-column.descr {
-  width: 200px;
+/**
+  Styles related to pickers, combo boxes, and relation widgets
+*/
+.onyx-picker-decorator .onyx-button {
+  padding: 12px 8px 12px 8px;
+  width: 150px;
 }
-.xv-list-column.icon {
-  width: 10px;
+.onyx-picker .onyx-menu-item {
+  text-align: left;
+  text-overflow: ellipsis;
 }
-.xv-list {
-  background: #f8f8f8;
+.picker-icon {
+  position: absolute;
+  right: 0;
+  margin: 0 10px 0 2px;
+  color: #070707;
 }
-.xv-list .xv-list-item > * {
-  display: inline-block;
-  vertical-align: middle;
+.xv-picker-button {
+  text-align: left;
 }
-.xv-list .xv-list-item {
-  background-color: #fdfdfd;
-  border-bottom: 1px solid #d7d7d7;
-  min-height: 32px;
+.xv-picker-button .picker-content {
+  max-width: 100px;
+  overflow: hidden;
 }
-.xv-list .xv-list-item.header {
-  padding-top: 0;
+.xv-picker-button.disabled {
+  color: #777777;
 }
-.xv-list .xv-list-item.inactive {
-  background-color: #d8d8d8;
+.xv-picker-label {
   color: #070707;
+  padding: 20px 8px 8px 8px;
+  text-align: right;
+  width: 130px;
 }
-.xv-list .xv-list-item.inactive .xv-list-column .xv-list-attr {
-  background: transparent;
-}
-.xv-list .xv-list-item.inactive .xv-list-column .xv-list-attr.placeholder {
-  color: #d8d8d8;
+.xv-picker-label.disabled {
+  color: #777777;
 }
-.xv-list .xv-list-item .xv-list-column .list-icon {
-  padding: 2px;
-  color: #666666;
-  vertical-align: sub;
-  border: 1px solid #efefef;
-  -webkit-border-radius: 2px;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
+.xv-combobox-note {
+  padding: 14px 3px 8px 3px;
+  text-align: left;
 }
-.xv-list .xv-list-item.item-selected {
-  background: #226b9a;
-  background-color: #1f608c;
-  background-image: -moz-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#226b9a), to(#1a4f77));
-  background-image: -webkit-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: -o-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: linear-gradient(to bottom, #226b9a, #1a4f77);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff226b9a', endColorstr='#ff1a4f77', GradientType=0);
+/*
+  Styles relating to the grid box
+*/
+/* Entire box including the grid and the summary panel */
+.xv-grid-box {
+  /**
+    This is the most general grid row that
+    is not specific to read-only or selected
+  */
 }
-.xv-list .xv-list-item.item-selected .xv-list-attr {
-  color: #fdfdfd;
+.xv-grid-box.small-panel {
+  width: 600px;
 }
-.xv-list .xv-list-item.item-selected .xv-list-attr.placeholder {
-  font-style: italic;
-  color: #99ccff;
+.xv-grid-box.medium-panel {
+  width: 700px;
 }
-.xv-list .xv-list-item.item-selected .xv-list-attr.hyperlink {
-  color: #ff6529;
+.xv-grid-box.large-panel {
+  width: 800px;
 }
-.xv-list .xv-list-item.item-selected .xv-list-attr.header {
-  background: #99ccff;
+.xv-grid-box .enyo-list-page > *:first-child .xv-grid-row {
+  border-top: 0;
 }
-.xv-list .xv-list-item .xv-list-item-gear {
-  position: absolute;
-  right: 0px;
-  z-index: 999;
+.xv-grid-box .xv-above-grid-list {
+  border: 0;
 }
-.xv-list.xv-grid-list {
+.xv-grid-box .xv-scroller {
   background: #f8f8f8;
 }
-.xv-list.xv-grid-list .xv-list-item > * {
-  vertical-align: top;
+.xv-limit-description .xv-grid-box .xv-grid-attr.bold {
+  font-weight: bold;
 }
-.xv-list.xv-grid-list .xv-list-item {
-  padding-top: 7px !important;
-  padding-bottom: 9px !important;
-  border-bottom: 1px solid #aaaaaa !important;
-  background: #f8f8f8;
+.xv-grid-box .xv-grid-attr.error {
+  color: #ff0000;
 }
-.xv-list.xv-grid-list .xv-list-item.item-selected {
-  background: #226b9a;
-  background-color: #1f608c;
-  background-image: -moz-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#226b9a), to(#1a4f77));
-  background-image: -webkit-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: -o-linear-gradient(top, #226b9a, #1a4f77);
-  background-image: linear-gradient(to bottom, #226b9a, #1a4f77);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff226b9a', endColorstr='#ff1a4f77', GradientType=0);
+.xv-grid-box .xv-grid-attr.emphasis {
+  color: #009000;
 }
-.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr {
-  color: #fdfdfd;
+.xv-grid-box .xv-grid-attr.warn {
+  color: #ff9c00;
 }
-.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.placeholder {
+.xv-grid-box .xv-grid-attr.italic {
   font-style: italic;
-  color: #99ccff;
 }
-.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.hyperlink {
-  color: #ff6529;
+.xv-grid-box .xv-grid-attr.placeholder {
+  font-style: italic;
+  color: #93a1a1;
 }
-.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.header {
-  background: #99ccff;
+.xv-grid-box .xv-grid-attr.hyperlink {
+  color: blue;
 }
-.xv-list.xv-grid-list .xv-list-item .xv-list-column {
-  vertical-align: top;
+.xv-grid-box .xv-gridbox-button {
+  color: #357ec7;
+  font-size: 18px;
+  border: none;
+  background: transparent;
 }
-.xv-list.xv-grid-list .xv-list-item .xv-list-column .xv-list-attr {
+.xv-grid-box .xv-grid-row {
   font-size: 12px;
+  background-color: #d8d8d8;
+  border-bottom: 1px solid #aaaaaa;
+  vertical-align: top;
+  /**
+      This is the grid header row
+    */
 }
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.last {
-  border-right: none;
+.xv-grid-box .xv-grid-row > * {
+  display: inline-block;
 }
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.name-column {
-  padding-left: 7px;
+.xv-grid-box .xv-grid-row .xv-grid-header {
+  background-color: #d7d7d7;
+  color: #0e0e0e;
+  font-size: .8em;
+  font-weight: bold;
+  text-transform: uppercase;
+  padding-top: 4px;
 }
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.first {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.second {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.third {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.short {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.small {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.medium {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column.descr {
-  padding-left: 7px;
-}
-.xv-list.xv-grid-list .xv-list-item .xv-list-column .xv-list-attr {
-  padding: 0px;
-}
-.xv-list-attr {
-  padding: 5px;
-  font-size: .8em;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  color: #070707;
-}
-.xv-list-attr.header {
-  padding: 4px;
-  background: #d8d8d8;
-  font-size: .7em;
-  font-weight: bold;
-  text-transform: uppercase;
-  color: #fdfdfd;
-}
-.xv-list-attr.footer {
-  padding: 4px;
-  background: #d8d8d8;
-  font-size: .7em;
-  font-weight: bold;
-  text-transform: uppercase;
-  color: #070707;
-}
-.xv-list-attr.right {
-  position: absolute;
-  right: 10px;
-}
-.xv-list-attr.text-align-right {
-  text-align: right;
-}
-.xv-list-attr.bold {
-  font-weight: bold;
-}
-.xv-list-attr.error {
-  color: #ff0000;
-}
-.xv-list-attr.emphasis {
-  color: #009000;
-}
-.xv-list-attr.warn {
-  color: #ff9c00;
-}
-.xv-list-attr.italic {
-  font-style: italic;
-}
-.xv-list-attr.placeholder {
-  font-style: italic;
-  color: #777777;
-}
-.xv-list-attr.hyperlink {
-  color: #357ec7;
-  cursor: pointer;
-}
-.xv-list-attr.disabled {
-  color: #777777;
-}
-/* Navigator */
-.xv-navigator-header {
-  font-size: small;
-  font-weight: bold;
-  text-transform: uppercase;
-  color: #ff6600;
-  padding-left: 20px;
-  border-bottom: 1px solid #0e0e0e;
-}
-.xv-workspace-header {
-  color: #fdfdfd;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  padding: 8px 0 0 8px;
-}
-/**
- * Default ListItem styles when using a ModelDecorator.
- */
-.xv-list .xv-model-decorator > .xv-list-item .xv-table {
-  display: table;
-  width: 100%;
-  table-layout: fixed;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-table .xv-cell {
-  display: table-cell;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr {
-  /**
-        * Default styling for a model's id (as designated by 'idAttribute')
-        */
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attribute-id {
-  color: #357ec7;
-  font-weight: bold;
-  cursor: pointer;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attribute-name {
-  font-weight: bold;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-number {
-  text-align: right;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-money {
-  text-align: right;
-}
-.xv-list .xv-model-decorator > .xv-list-item .xv-list-column.xv-list-attr.xm-attributetype-date {
-  text-align: right;
-}
-.xv-list .xv-model-decorator > .xv-list-item.item-selected .xv-list-attr {
-  color: white;
-}
-.xv-list .xv-model-decorator > .xv-list-item.item-selected .xv-list-attr.xm-attribute-id {
-  color: #ff6529;
-}
-/**
-  Styles related to pickers, combo boxes, and relation widgets
-*/
-.onyx-picker-decorator .onyx-button {
-  padding: 12px 8px 12px 8px;
-  width: 150px;
-}
-.onyx-picker .onyx-menu-item {
-  text-align: left;
-  text-overflow: ellipsis;
-}
-.picker-icon {
-  position: absolute;
-  right: 0;
-  margin: 0 10px 0 2px;
-  color: #070707;
-}
-.xv-picker-button {
-  text-align: left;
-}
-.xv-picker-button .picker-content {
-  max-width: 100px;
-  overflow: hidden;
-}
-.xv-picker-button.disabled {
-  color: #777777;
-}
-.xv-picker-label {
-  color: #070707;
-  padding: 20px 8px 8px 8px;
-  text-align: right;
-  width: 130px;
-}
-.xv-picker-label.disabled {
-  color: #777777;
-}
-.xv-combobox-note {
-  padding: 14px 3px 8px 3px;
-  text-align: left;
-}
-/*
-  Styles relating to the grid box
-*/
-/* Entire box including the grid and the summary panel */
-.xv-grid-box {
-  /**
-    This is the most general grid row that
-    is not specific to read-only or selected
-  */
-}
-.xv-grid-box.small-panel {
-  width: 600px;
-}
-.xv-grid-box.medium-panel {
-  width: 700px;
-}
-.xv-grid-box.large-panel {
-  width: 800px;
-}
-.xv-grid-box .enyo-list-page > *:first-child .xv-grid-row {
-  border-top: 0;
-}
-.xv-grid-box .xv-above-grid-list {
-  border: 0;
-}
-.xv-grid-box .xv-scroller {
-  background: #f8f8f8;
-}
-.xv-limit-description .xv-grid-box .xv-grid-attr.bold {
-  font-weight: bold;
-}
-.xv-grid-box .xv-grid-attr.error {
-  color: #ff0000;
-}
-.xv-grid-box .xv-grid-attr.emphasis {
-  color: #009000;
-}
-.xv-grid-box .xv-grid-attr.warn {
-  color: #ff9c00;
-}
-.xv-grid-box .xv-grid-attr.italic {
-  font-style: italic;
-}
-.xv-grid-box .xv-grid-attr.placeholder {
-  font-style: italic;
-  color: #93a1a1;
-}
-.xv-grid-box .xv-grid-attr.hyperlink {
-  color: blue;
-}
-.xv-grid-box .xv-gridbox-button {
-  color: #357ec7;
-  font-size: 18px;
-  border: none;
-  background: transparent;
-}
-.xv-grid-box .xv-grid-row {
-  font-size: 12px;
-  background-color: #d8d8d8;
-  border-bottom: 1px solid #aaaaaa;
-  vertical-align: top;
-  /**
-      This is the grid header row
-    */
-}
-.xv-grid-box .xv-grid-row > * {
-  display: inline-block;
-}
-.xv-grid-box .xv-grid-row .xv-grid-header {
-  background-color: #d7d7d7;
-  color: #0e0e0e;
-  font-size: .8em;
-  font-weight: bold;
-  text-transform: uppercase;
-  padding-top: 4px;
-}
-.xv-grid-box .xv-grid-row .xv-grid-header.last {
-  border-right: none;
+.xv-grid-box .xv-grid-row .xv-grid-header.last {
+  border-right: none;
 }
 .xv-grid-box .xv-grid-row > * {
   padding: 6px 4px;
@@ -2960,6 +2687,281 @@ a,
   text-align: center;
   font-size: 24px;
 }
+/**
+  Styles relating to Lists
+*/
+.xv-list-header {
+  background-color: #d8d8d8;
+  color: #fdfdfd;
+  font-size: .6em;
+  font-weight: bold;
+  text-transform: uppercase;
+  padding-top: 4px;
+  padding-bottom: 4px;
+  border-bottom: 1px solid #aaaaaa;
+}
+.xv-list-header .xv-list-column.last {
+  border-right: none;
+}
+.xv-list-header .xv-list-column.name-column,
+.xv-list-header .xv-list-column.first,
+.xv-list-header .xv-list-column.second,
+.xv-list-header .xv-list-column.third,
+.xv-list-header .xv-list-column.short,
+.xv-list-header .xv-list-column.small,
+.xv-list-header .xv-list-column.medium,
+.xv-list-header .xv-list-column.descr {
+  padding-left: 7px;
+}
+/* List */
+.xv-list-column.line-number {
+  width: 30px;
+  text-align: right;
+}
+.xv-list-column.name-column {
+  width: 200px;
+}
+.xv-list-column.right-column {
+  width: 100px;
+  text-align: right;
+}
+.xv-list-column.short {
+  width: 100px;
+}
+.xv-list-column.small {
+  width: 125px;
+}
+.xv-list-column.medium {
+  width: 150px;
+}
+.xv-list-column.first {
+  width: 300px;
+}
+.xv-list-column.second {
+  width: 200px;
+}
+.xv-list-column.third {
+  width: 100px;
+}
+.xv-list-column.money,
+.xv-list-column.quantity {
+  width: 75px;
+  text-align: right;
+}
+.xv-list-column.descr {
+  width: 200px;
+}
+.xv-list-column.icon {
+  width: 10px;
+}
+.xv-list {
+  background: #f8f8f8;
+}
+.xv-list .xv-list-item > * {
+  display: inline-block;
+  vertical-align: middle;
+}
+.xv-list .xv-list-item {
+  background-color: #fdfdfd;
+  border-bottom: 1px solid #d7d7d7;
+  min-height: 32px;
+}
+.xv-list .xv-list-item.header {
+  padding-top: 0;
+}
+.xv-list .xv-list-item.inactive {
+  background-color: #d8d8d8;
+  color: #070707;
+}
+.xv-list .xv-list-item.inactive .xv-list-column .xv-list-attr {
+  background: transparent;
+}
+.xv-list .xv-list-item.inactive .xv-list-column .xv-list-attr.placeholder {
+  color: #d8d8d8;
+}
+.xv-list .xv-list-item .xv-list-column .list-icon {
+  padding: 2px;
+  color: #666666;
+  vertical-align: sub;
+  border: 1px solid #efefef;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.xv-list .xv-list-item.item-selected {
+  background: #226b9a;
+  background-color: #1f608c;
+  background-image: -moz-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#226b9a), to(#1a4f77));
+  background-image: -webkit-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: -o-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: linear-gradient(to bottom, #226b9a, #1a4f77);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff226b9a', endColorstr='#ff1a4f77', GradientType=0);
+}
+.xv-list .xv-list-item.item-selected .xv-list-attr {
+  color: #fdfdfd;
+}
+.xv-list .xv-list-item.item-selected .xv-list-attr.placeholder {
+  font-style: italic;
+  color: #99ccff;
+}
+.xv-list .xv-list-item.item-selected .xv-list-attr.hyperlink {
+  color: #ff6529;
+}
+.xv-list .xv-list-item.item-selected .xv-list-attr.header {
+  background: #99ccff;
+}
+.xv-list .xv-list-item .xv-list-item-gear {
+  position: absolute;
+  right: 0px;
+  z-index: 999;
+}
+.xv-list.xv-grid-list {
+  background: #f8f8f8;
+}
+.xv-list.xv-grid-list .xv-list-item > * {
+  vertical-align: top;
+}
+.xv-list.xv-grid-list .xv-list-item {
+  padding-top: 7px !important;
+  padding-bottom: 9px !important;
+  border-bottom: 1px solid #aaaaaa !important;
+  background: #f8f8f8;
+}
+.xv-list.xv-grid-list .xv-list-item.item-selected {
+  background: #226b9a;
+  background-color: #1f608c;
+  background-image: -moz-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#226b9a), to(#1a4f77));
+  background-image: -webkit-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: -o-linear-gradient(top, #226b9a, #1a4f77);
+  background-image: linear-gradient(to bottom, #226b9a, #1a4f77);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff226b9a', endColorstr='#ff1a4f77', GradientType=0);
+}
+.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr {
+  color: #fdfdfd;
+}
+.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.placeholder {
+  font-style: italic;
+  color: #99ccff;
+}
+.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.hyperlink {
+  color: #ff6529;
+}
+.xv-list.xv-grid-list .xv-list-item.item-selected .xv-list-attr.header {
+  background: #99ccff;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column {
+  vertical-align: top;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column .xv-list-attr {
+  font-size: 12px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.last {
+  border-right: none;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.name-column {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.first {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.second {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.third {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.short {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.small {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.medium {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column.descr {
+  padding-left: 7px;
+}
+.xv-list.xv-grid-list .xv-list-item .xv-list-column .xv-list-attr {
+  padding: 0px;
+}
+.xv-list-attr {
+  padding: 5px;
+  font-size: .8em;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  color: #070707;
+}
+.xv-list-attr.header {
+  padding: 4px;
+  background: #d8d8d8;
+  font-size: .7em;
+  font-weight: bold;
+  text-transform: uppercase;
+  color: #fdfdfd;
+}
+.xv-list-attr.footer {
+  padding: 4px;
+  background: #d8d8d8;
+  font-size: .7em;
+  font-weight: bold;
+  text-transform: uppercase;
+  color: #070707;
+}
+.xv-list-attr.right {
+  position: absolute;
+  right: 10px;
+}
+.xv-list-attr.text-align-right {
+  text-align: right;
+}
+.xv-list-attr.bold {
+  font-weight: bold;
+}
+.xv-list-attr.error {
+  color: #ff0000;
+}
+.xv-list-attr.emphasis {
+  color: #009000;
+}
+.xv-list-attr.warn {
+  color: #ff9c00;
+}
+.xv-list-attr.italic {
+  font-style: italic;
+}
+.xv-list-attr.placeholder {
+  font-style: italic;
+  color: #777777;
+}
+.xv-list-attr.hyperlink {
+  color: #357ec7;
+  cursor: pointer;
+}
+.xv-list-attr.disabled {
+  color: #777777;
+}
+/* Navigator */
+.xv-navigator-header {
+  font-size: small;
+  font-weight: bold;
+  text-transform: uppercase;
+  color: #ff6600;
+  padding-left: 20px;
+  border-bottom: 1px solid #0e0e0e;
+}
+.xv-workspace-header {
+  color: #fdfdfd;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  padding: 8px 0 0 8px;
+}
 /**
   Styles relating to widgets in the pullout
 */
index daedb9c..6a49dc5 100644 (file)
@@ -585,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,
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 e7ccd5e..7130a80 100644 (file)
@@ -38,19 +38,20 @@ 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},
@@ -59,7 +60,8 @@ trailing:true, white:true*/
     resizeHandler: function () {
       this.inherited(arguments);
       if (this.$.notifyPopup.showing) {
-        this.$.notifyPopup.applyStyle("opacity", 1); // XXX not sure why this hack is necessary.
+        // This is a fix for an enyo bug that renders the popup as clear
+        this.$.notifyPopup.applyStyle("opacity", 1);
       }
     },
     activate: function () {
@@ -178,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;
@@ -258,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());
@@ -281,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
@@ -302,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);
         }
@@ -313,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) {
@@ -331,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
@@ -346,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
@@ -366,7 +358,7 @@ trailing:true, white:true*/
         }
         this._activeNotify = activeIndex;
 
-        notifyButtons[activeIndex].addClass("onyx-blue");
+        notifyButtons[activeIndex].addClass("selected");
       }
     },
     /**
@@ -447,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 a1a793f..4966429 100644 (file)
@@ -19,7 +19,6 @@ regexp:true, undef:true, trailing:true, white:true */
       attr: null,
       scale: 0,
       formatting: true,
-      type: "number",
       label: "",
       showLabel: true
     },
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 25801b5..f2b9145 100755 (executable)
@@ -114,9 +114,15 @@ var app;
     var extensionLocation = extension.location === "npm" ? extension.location : extension.location + "/source";
     useClientDir(extensionLocation + "/" + extension.name + "/client", X.path.join(getExtensionDir(extension), "client"));
   };
-  var loadExtensionRoutes = function (extension) {
-    var manifest = JSON.parse(X.fs.readFileSync(X.path.join(getExtensionDir(extension),
-        "database/source/manifest.js")));
+  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(getExtensionDir(extension),
@@ -149,7 +155,7 @@ var app;
           return;
         }
         useClientDir("/client", "../enyo-client/application");
-        _.each(results, loadExtensionRoutes);
+        _.each(results, loadExtensionServerside);
         _.each(results, loadExtensionClientside);
       }
     });
@@ -168,11 +174,9 @@ var app;
  */
 
 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.
@@ -294,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();
@@ -393,6 +398,7 @@ var that = this;
 
 app.use(express.favicon(__dirname + '/views/login/assets/favicon.ico'));
 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);
@@ -638,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 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);
index b4c69d5..16858d8 100644 (file)
@@ -7,8 +7,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
 (function () {
   "use strict";
 
-  var ursa = require("ursa"),
-    exec = require("child_process").exec,
+  var exec = require("child_process").exec,
     forge = require("node-forge"),
     spawn = require("child_process").spawn,
     async = require("async"),
@@ -29,10 +28,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
         res.send({isError: true, error: err});
       },
       genKey = function (model, result) {
-        /**
-          * This is REALLY slow in pure javascript. ursa is much faster.
-          * @See: https://github.com/digitalbazaar/forge/issues/125
-        forge.pki.rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
+        forge.pki.rsa.generateKeyPair({bits: 2048, workers: -1}, function (err, keypair) {
           if (err) {
             res.send({isError: true, message: "Error generating keypair: " + err.message, error: err});
             return;
@@ -40,16 +36,6 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
 
           fetchSuccess(model, result, keypair);
         });
-        */
-
-        // Use ursa for the key gen and then convert to forge's format.
-        var keypair = ursa.generatePrivateKey();
-        var keys = {
-          privateKey: forge.pki.privateKeyFromPem(keypair.toPrivatePem().toString()),
-          publicKey: forge.pki.publicKeyFromPem(keypair.toPublicPem().toString())
-        };
-
-        fetchSuccess(model, result, keys);
       },
       sendP12 = function (keys) {
         // It's possible and much easier to generate the p12 file without a
index c2a8df5..49fb74e 100644 (file)
@@ -17,6 +17,7 @@
     <!-- 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 < extensionJsArray.length; i++) { %>
       <script src="/<%= org %>/client/build/client-code?uuid=<%= extensionJsArray[i] %>&language=js"></script>
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 1a94b39..382a101 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"
-            },
-            "he": {
-              "version": "0.3.6",
-              "from": "he@~0.3.6"
+            "aws-sign": {
+              "version": "0.3.0",
+              "from": "aws-sign@~0.3.0"
             },
-            "punycode": {
-              "version": "1.2.4",
-              "from": "punycode@~1.2.3"
+            "oauth-sign": {
+              "version": "0.3.0",
+              "from": "oauth-sign@~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"
+            "cookie-jar": {
+              "version": "0.3.0",
+              "from": "cookie-jar@~0.3.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"
+            "node-uuid": {
+              "version": "1.4.1",
+              "from": "node-uuid@~1.4.0"
             },
-            "xoauth2": {
-              "version": "0.1.8",
-              "from": "xoauth2@~0.1"
-            }
-          }
-        },
-        "optimist": {
-          "version": "0.6.1",
-          "from": "optimist@*",
-          "dependencies": {
-            "wordwrap": {
-              "version": "0.0.2",
-              "from": "wordwrap@~0.0.2"
+            "mime": {
+              "version": "1.2.11",
+              "from": "mime@~1.2.9"
             },
-            "minimist": {
-              "version": "0.0.9",
-              "from": "minimist@~0.0.1",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.9.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"
+                    }
+                  }
+                },
+                "async": {
+                  "version": "0.9.0",
+                  "from": "async@~0.9.0"
+                }
+              }
             }
           }
-        }
-      }
-    },
-    "node-forge": {
-      "version": "0.6.2",
-      "from": "node-forge@0.6.x"
-    },
-    "npm": {
-      "version": "1.4.16",
-      "from": "npm@1.4.x",
-      "resolved": "https://registry.npmjs.org/npm/-/npm-1.4.16.tgz",
-      "dependencies": {
-        "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"
+        "async": {
+          "version": "0.2.6",
+          "from": "async@0.2.6",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz"
         },
-        "chmodr": {
+        "gapitoken": {
           "version": "0.1.0",
-          "from": "chmodr@latest"
-        },
-        "chownr": {
-          "version": "0.0.1",
-          "from": "../chownr"
-        },
-        "cmd-shim": {
-          "version": "1.1.1",
-          "from": "cmd-shim@latest",
-          "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-1.1.1.tgz"
-        },
-        "columnify": {
-          "version": "1.1.0",
-          "from": "columnify@latest",
-          "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.1.0.tgz",
-          "dependencies": {
-            "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": {
-                "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"
-                }
-              }
-            },
-            "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": {
-                "underscore": {
-                  "version": "1.6.0",
-                  "from": "underscore@>= 1.3.0",
-                  "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
-                }
-              }
-            }
-          }
-        },
-        "editor": {
-          "version": "0.1.0",
-          "from": "editor@latest",
-          "resolved": "https://registry.npmjs.org/editor/-/editor-0.1.0.tgz"
-        },
-        "fstream": {
-          "version": "0.1.27",
-          "from": "fstream@~0.1.26"
-        },
-        "fstream-npm": {
-          "version": "0.1.7",
-          "from": "fstream-npm@latest",
-          "dependencies": {
-            "fstream-ignore": {
-              "version": "0.0.8",
-              "from": "fstream-ignore@~0.0",
-              "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-0.0.8.tgz"
-            }
-          }
-        },
-        "github-url-from-git": {
-          "version": "1.1.1",
-          "from": "github-url-from-git@1.1.1",
-          "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.1.1.tgz"
-        },
-        "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.2",
-          "from": "glob@latest",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-4.0.2.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": "0.1.0",
-          "from": "init-package-json@latest",
-          "dependencies": {
-            "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": "0.3.0",
-          "from": "minimatch@latest",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
-          "dependencies": {
-            "sigmund": {
-              "version": "1.0.0",
-              "from": "sigmund@~1.0.0",
-              "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz"
-            }
-          }
-        },
-        "mkdirp": {
-          "version": "0.3.5",
-          "from": "mkdirp@latest"
-        },
-        "node-gyp": {
-          "version": "0.13.1",
-          "from": "node-gyp@~0.13.0",
-          "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-0.13.1.tgz"
-        },
-        "nopt": {
-          "version": "3.0.0",
-          "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.2",
-          "from": "npm-registry-client@latest"
-        },
-        "npm-user-validate": {
-          "version": "0.1.0",
-          "from": "npm-user-validate@latest"
-        },
-        "npmconf": {
-          "version": "1.0.5",
-          "from": "npmconf@latest",
+          "from": "gapitoken@0.1.0",
+          "resolved": "https://registry.npmjs.org/gapitoken/-/gapitoken-0.1.0.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",
+            "jws": {
+              "version": "0.0.2",
+              "from": "jws@0.0.2",
+              "resolved": "https://registry.npmjs.org/jws/-/jws-0.0.2.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"
+                "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"
                 }
               }
             }
           }
-        },
-        "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.2",
-          "from": "read-package-json@latest",
-          "dependencies": {
-            "normalize-package-data": {
-              "version": "0.3.0",
-              "from": "normalize-package-data@^0.3.0",
-              "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-0.3.0.tgz"
-            }
-          }
-        },
-        "request": {
-          "version": "2.30.0",
-          "from": "request@latest",
+        }
+      }
+    },
+    "html5": {
+      "version": "0.3.13",
+      "from": "html5@0.3.13",
+      "resolved": "https://registry.npmjs.org/html5/-/html5-0.3.13.tgz",
+      "dependencies": {
+        "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": {
-            "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.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",
+            "htmlparser2": {
+              "version": "3.7.3",
+              "from": "htmlparser2@>= 3.1.5 <4",
+              "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.7.3.tgz",
               "dependencies": {
-                "combined-stream": {
-                  "version": "0.0.4",
-                  "from": "combined-stream@~0.0.4",
+                "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": {
-                    "delayed-stream": {
-                      "version": "0.0.5",
-                      "from": "delayed-stream@0.0.5"
+                    "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"
                     }
                   }
                 },
-                "async": {
-                  "version": "0.2.9",
-                  "from": "async@~0.2.9"
+                "entities": {
+                  "version": "1.0.0",
+                  "from": "entities@1.0"
                 }
               }
             },
-            "tunnel-agent": {
+            "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": "tunnel-agent@~0.3.0"
+              "from": "cssom@~0.3.0"
             },
-            "http-signature": {
-              "version": "0.10.0",
-              "from": "http-signature@~0.10.0",
+            "cssstyle": {
+              "version": "0.2.14",
+              "from": "cssstyle@~0.2.9"
+            },
+            "contextify": {
+              "version": "0.1.8",
+              "from": "contextify@~0.1.5",
               "dependencies": {
-                "assert-plus": {
-                  "version": "0.1.2",
-                  "from": "assert-plus@0.1.2"
-                },
-                "asn1": {
-                  "version": "0.1.11",
-                  "from": "asn1@0.1.11"
+                "bindings": {
+                  "version": "1.2.1",
+                  "from": "bindings@*",
+                  "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
                 },
-                "ctype": {
-                  "version": "0.5.2",
-                  "from": "ctype@0.5.2"
+                "nan": {
+                  "version": "1.0.0",
+                  "from": "nan@~1.0.0"
                 }
               }
-            },
-            "oauth-sign": {
-              "version": "0.3.0",
-              "from": "oauth-sign@~0.3.0"
-            },
-            "hawk": {
-              "version": "1.0.0",
-              "from": "hawk@~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": {
-                "hoek": {
-                  "version": "0.9.1",
-                  "from": "hoek@0.9.x"
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@2"
                 },
-                "boom": {
-                  "version": "0.4.2",
-                  "from": "boom@0.4.x"
+                "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"
+                    }
+                  }
                 },
-                "cryptiles": {
-                  "version": "0.2.2",
-                  "from": "cryptiles@0.2.x"
+                "once": {
+                  "version": "1.3.0",
+                  "from": "once@^1.3.0",
+                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.0.tgz"
                 },
-                "sntp": {
-                  "version": "0.2.4",
-                  "from": "sntp@0.2.x"
+                "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"
                 }
               }
-            },
-            "aws-sign2": {
-              "version": "0.5.0",
-              "from": "aws-sign2@~0.5.0"
             }
           }
         },
-        "retry": {
-          "version": "0.6.0",
-          "from": "retry"
-        },
-        "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"
+        "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"
+            }
+          }
         },
-        "sha": {
-          "version": "1.2.4",
-          "from": "sha@latest",
-          "resolved": "https://registry.npmjs.org/sha/-/sha-1.2.4.tgz",
+        "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.27-1",
+              "version": "1.0.31",
               "from": "readable-stream@1.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
+              "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",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+                  "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"
+                  "from": "isarray@0.0.1"
                 },
                 "string_decoder": {
-                  "version": "0.10.25-1",
+                  "version": "0.10.31",
                   "from": "string_decoder@~0.10.x",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.25-1.tgz"
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@~2.0.1"
                 }
               }
             }
           }
         },
-        "slide": {
-          "version": "1.1.5",
-          "from": "slide@latest"
-        },
-        "sorted-object": {
-          "version": "1.0.0",
-          "from": "sorted-object@"
-        },
-        "tar": {
-          "version": "0.1.19",
-          "from": "tar@0.1.19",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-0.1.19.tgz"
-        },
-        "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"
+        "console-browserify": {
+          "version": "0.1.6",
+          "from": "console-browserify@0.1.x"
         },
-        "inherits": {
-          "version": "2.0.1",
-          "from": "inherits@"
-        }
-      }
-    },
-    "oauth2orize": {
-      "version": "0.1.0",
-      "from": "oauth2orize@0.1.x",
-      "dependencies": {
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@0.7.x"
+        "exit": {
+          "version": "0.1.2",
+          "from": "exit@0.1.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"
-        }
-      }
+    "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"
     },
-    "passport": {
-      "version": "0.1.18",
-      "from": "passport@0.1.x",
+    "less": {
+      "version": "1.5.0",
+      "from": "less@1.5.0",
+      "resolved": "https://registry.npmjs.org/less/-/less-1.5.0.tgz",
       "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
+        "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"
+                }
+              }
+            }
+          }
         },
-        "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"
+        "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"
+            }
+          }
         }
       }
     },
-    "passport-http-bearer": {
-      "version": "0.2.1",
-      "from": "passport-http-bearer@0.2.x",
+    "mocha": {
+      "version": "1.9.0",
+      "from": "mocha@1.9.x",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.9.0.tgz",
       "dependencies": {
-        "pkginfo": {
-          "version": "0.2.3",
-          "from": "pkginfo@0.2.x"
+        "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-local": {
-      "version": "0.1.6",
-      "from": "passport-local@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-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"
-        }
-      }
+    "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"
     },
-    "passport-oauth2-jwt-bearer": {
-      "version": "0.1.1",
-      "from": "passport-oauth2-jwt-bearer@0.1.x",
+    "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"
+            "chalk": {
+              "version": "0.4.0",
+              "from": "chalk@^0.4.0",
+              "dependencies": {
+                "has-color": {
+                  "version": "0.1.7",
+                  "from": "has-color@~0.1.0"
+                },
+                "ansi-styles": {
+                  "version": "1.0.0",
+                  "from": "ansi-styles@~1.0.0"
+                },
+                "strip-ansi": {
+                  "version": "0.1.1",
+                  "from": "strip-ansi@~0.1.0"
+                }
+              }
             },
-            "semver": {
-              "version": "2.2.1",
-              "from": "semver@=2.2.1",
-              "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz"
+            "configstore": {
+              "version": "0.3.1",
+              "from": "configstore@^0.3.0",
+              "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.3.1.tgz",
+              "dependencies": {
+                "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"
+                }
+              }
             },
-            "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",
+            "request": {
+              "version": "2.40.0",
+              "from": "request@^2.36.0",
+              "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz",
               "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@~1.0.0"
+                "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": {
+                    "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"
+                    }
+                  }
                 },
-                "string_decoder": {
-                  "version": "0.10.25-1",
-                  "from": "string_decoder@~0.10.x"
+                "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"
                 },
-                "debuglog": {
-                  "version": "0.0.2",
-                  "from": "debuglog@0.0.2",
-                  "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-0.0.2.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"
                 }
               }
             },
-            "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",
-              "dependencies": {
-                "sax": {
-                  "version": "0.6.0",
-                  "from": "sax@>=0.1.1"
-                }
-              }
+            "semver": {
+              "version": "2.3.2",
+              "from": "semver@^2.3.0",
+              "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz"
+            }
+          }
+        },
+        "minimatch": {
+          "version": "0.2.14",
+          "from": "minimatch@~0.2.14",
+          "dependencies": {
+            "lru-cache": {
+              "version": "2.5.0",
+              "from": "lru-cache@2"
             },
-            "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",
+            "sigmund": {
+              "version": "1.0.0",
+              "from": "sigmund@~1.0.0"
+            }
+          }
+        },
+        "ps-tree": {
+          "version": "0.0.3",
+          "from": "ps-tree@0.0.3",
+          "dependencies": {
+            "event-stream": {
+              "version": "0.5.3",
+              "from": "event-stream@~0.5",
               "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",
+                "optimist": {
+                  "version": "0.2.8",
+                  "from": "optimist@0.2",
                   "dependencies": {
-                    "amdefine": {
-                      "version": "0.1.0",
-                      "from": "amdefine@>=0.0.4"
+                    "wordwrap": {
+                      "version": "0.0.2",
+                      "from": "wordwrap@>=0.0.1 <0.1.0"
                     }
                   }
                 }
         }
       }
     },
-    "pg": {
-      "version": "0.14.1",
-      "from": "pg@0.14.x",
+    "npm": {
+      "version": "1.4.24",
+      "from": "npm@1.4.x",
       "dependencies": {
-        "generic-pool": {
-          "version": "2.0.4",
-          "from": "generic-pool@~2.0.2"
+        "abbrev": {
+          "version": "1.0.5",
+          "from": "abbrev@latest",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
         },
-        "deprecate": {
-          "version": "0.1.0",
-          "from": "deprecate@~0.1.0"
-        }
-      }
-    },
-    "request": {
-      "version": "2.14.0",
-      "from": "request@2.14.x",
-      "dependencies": {
-        "form-data": {
+        "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": "form-data@~0.0.3",
+          "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": {
+            "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": {
+                "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"
+                }
+              }
+            },
+            "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": {
+                "underscore": {
+                  "version": "1.6.0",
+                  "from": "underscore@>= 1.3.0",
+                  "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
+                }
+              }
+            }
+          }
+        },
+        "editor": {
+          "version": "0.1.0",
+          "from": "editor@latest",
+          "resolved": "https://registry.npmjs.org/editor/-/editor-0.1.0.tgz"
+        },
+        "fstream": {
+          "version": "1.0.0",
+          "from": "fstream@latest"
+        },
+        "fstream-npm": {
+          "version": "1.0.0",
+          "from": "fstream-npm@latest",
+          "dependencies": {
+            "fstream-ignore": {
+              "version": "1.0.1",
+              "from": "fstream-ignore@^1.0.0"
+            }
+          }
+        },
+        "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"
+        },
+        "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": {
+            "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": {
-            "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.1.22",
-              "from": "async@~0.1.9"
+            "sigmund": {
+              "version": "1.0.0",
+              "from": "sigmund@~1.0.0",
+              "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz"
             }
           }
         },
-        "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",
+        "mkdirp": {
+          "version": "0.5.0",
+          "from": "mkdirp@latest",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
           "dependencies": {
-            "keypress": {
-              "version": "0.1.0",
-              "from": "keypress@0.1.x"
+            "minimist": {
+              "version": "0.0.8",
+              "from": "minimist@0.0.8",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
             }
           }
-        }
-      }
-    },
-    "socket.io": {
-      "version": "0.9.16",
-      "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",
+        },
+        "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": {
-            "uglify-js": {
-              "version": "1.2.5",
-              "from": "uglify-js@1.2.5"
-            },
-            "ws": {
-              "version": "0.4.31",
-              "from": "ws@0.4.x",
-              "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"
-                }
-              }
-            },
-            "xmlhttprequest": {
-              "version": "1.4.2",
-              "from": "xmlhttprequest@1.4.2"
-            },
-            "active-x-obfuscator": {
-              "version": "0.0.1",
-              "from": "active-x-obfuscator@0.0.1",
+            "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": {
-                "zeparser": {
-                  "version": "0.0.5",
-                  "from": "zeparser@0.0.5"
+                "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"
                 }
               }
             }
           }
         },
-        "policyfile": {
-          "version": "0.0.4",
-          "from": "policyfile@0.0.4",
-          "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz"
+        "npmlog": {
+          "version": "0.1.1",
+          "from": "npmlog@latest"
         },
-        "base64id": {
+        "once": {
+          "version": "1.3.0",
+          "from": "once@latest"
+        },
+        "opener": {
+          "version": "1.3.0",
+          "from": "opener@latest"
+        },
+        "osenv": {
           "version": "0.1.0",
-          "from": "base64id@0.1.0"
+          "from": "osenv@~0.1.0"
         },
-        "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"
+        "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"
         },
-        "eyes": {
-          "version": "0.1.8",
-          "from": "eyes@0.1.x"
+        "read": {
+          "version": "1.0.5",
+          "from": "read@latest",
+          "dependencies": {
+            "mute-stream": {
+              "version": "0.0.4",
+              "from": "mute-stream@~0.0.4"
+            }
+          }
         },
-        "pkginfo": {
-          "version": "0.3.0",
-          "from": "pkginfo@0.3.x"
+        "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"
+            }
+          }
         },
-        "request": {
-          "version": "2.16.6",
-          "from": "request@2.16.x",
+        "read-package-json": {
+          "version": "1.2.6",
+          "from": "read-package-json@latest",
           "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"
+            "normalize-package-data": {
+              "version": "1.0.0",
+              "from": "normalize-package-data@^1.0.0"
             }
           }
         },
-        "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"
-        },
-        "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"
+    },
+    "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 8f1faad..88d940f 100644 (file)
@@ -2,7 +2,7 @@
   "author": "xTuple <dev@xtuple.com>",
   "name": "xtuple",
   "description": "xTuple Enterprise Resource Planning Mobile-Web client",
-  "version": "4.6.0",
+  "version": "4.7.0-beta",
   "repository": {
     "type": "git",
     "url": "https://github.com/xtuple/xtuple.git"
     "underscore": "1.4.x",
     "winston": "0.7.x",
     "underscore.string": "~2.3.3",
-    "ursa":"0.8.x"
+    "xtuple-linguist": "0.1.x",
+    "jquery": "~2.1.1"
   },
   "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",
-    "xtuple-documentation": "~0.0.1",
-    "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": {
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);
index a1779db..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 ""
index 611107a..469fbd6 100644 (file)
@@ -5,14 +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');
 
 /*
@@ -31,6 +34,93 @@ var _ = require('underscore'),
 
   var creds;
 
+  var buildAll = function (specs, creds, buildAllCallback) {
+    async.series([
+      function (done) {
+        // step 0: init the database, if requested
+
+        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
+          initDatabase(specs[0], creds, function (err, res) {
+            specs[0].wasInitialized = true;
+            done(err, res);
+          });
+          return;
+        } else {
+          done();
+        }
+
+      },
+      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) {
+            done(err);
+            return;
+          }
+          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);
+        });
+      },
+      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;
+          }
+          var returnMessage = "\n";
+          _.each(specs, function (spec) {
+            returnMessage += "Database: " + spec.database + '\nDirectories:\n';
+            _.each(spec.extensions, function (ext) {
+              returnMessage += '  ' + ext + '\n';
+            });
+          });
+          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 = {},
@@ -39,7 +129,7 @@ var _ = require('underscore'),
       getRegisteredExtensions = function (database, callback) {
         var credsClone = JSON.parse(JSON.stringify(creds));
         credsClone.database = database;
-        buildDatabaseUtil.inspectDatabaseExtensions(credsClone, function (err, paths) {
+        inspectDatabaseExtensions(credsClone, function (err, paths) {
           callback(null, {
             extensions: paths,
             database: database,
@@ -51,81 +141,6 @@ var _ = require('underscore'),
           });
         });
       },
-      buildAll = function (specs, creds, buildAllCallback) {
-        async.series([
-          function (done) {
-            // step 0: init the database, if requested
-
-            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) {
-                specs[0].wasInitialized = true;
-                done(err, res);
-              });
-              return;
-            } else {
-              done();
-            }
-
-          },
-          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) {
-                done(err);
-                return;
-              }
-              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);
-            });
-          },
-          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;
-              }
-              var returnMessage = "\n";
-              _.each(specs, function (spec) {
-                returnMessage += "Database: " + spec.database + '\nDirectories:\n';
-                _.each(spec.extensions, function (ext) {
-                  returnMessage += '  ' + ext + '\n';
-                });
-              });
-              done(null, "Build succeeded." + returnMessage);
-            });
-          }
-        ], function (err, results) {
-          buildAllCallback(err, results && results[results.length - 1]);
-        });
-      },
       config;
 
     if (options.config) {
@@ -176,7 +191,7 @@ var _ = require('underscore'),
         // an unmobilized build
         buildSpecs.extensions = options.extension ?
           [options.extension] :
-          buildDatabaseUtil.defaultExtensions;
+          defaultExtensions;
       }
       buildSpecs.initialize = true;
       buildSpecs.keepSql = options.keepSql;
index 2e0826f..adcf21d 100755 (executable)
@@ -73,30 +73,18 @@ var _ = require('underscore'),
           return;
         }
         fs.readFile(path.join(__dirname, "build", extName + ".css"), "utf8", function (err, cssCode) {
-          // 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;
-            }
-            var manifestDetails = JSON.parse(manifestContents);
-            if (!manifestDetails.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(cssCode, extName, packageDetails.version, "css") +
-                  constructQuery(jsCode, extName, packageDetails.version, "js"));
-              });
-
-            } else {
-              callback(null, constructQuery(cssCode, extName, manifestDetails.version, "css") +
-                constructQuery(jsCode, extName, manifestDetails.version, "js"));
-            }
-          });
+          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;
+          }
+          if (!version) {
+            // if the extensions don't declare their version, default to the package version
+            version = require(path.resolve(__dirname, "../../package.json")).version;
+          }
+          callback(null, constructQuery(cssCode, extName, version, "css") +
+            constructQuery(jsCode, extName, version, "js"));
         });
       });
     }
index aadd5d0..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 () {
@@ -73,15 +74,20 @@ var  async = require('async'),
           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" :
@@ -90,8 +96,7 @@ var  async = require('async'),
               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
@@ -189,16 +194,9 @@ 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) {
+        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");
diff --git a/scripts/lib/build_database_util.js b/scripts/lib/build_database_util.js
deleted file mode 100644 (file)
index 8ce8b9c..0000000
+++ /dev/null
@@ -1,618 +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 defaultExtensions = [
-    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')
-  ];
-
-  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;
-  };
-
-  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
-      //
-    });
-  };
-
-  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);
-      }
-    });
-  };
-
-  //
-  // 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);
-          }
-          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);
-    }
-  };
-
-
-  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.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.defaultExtensions = defaultExtensions;
-  exports.inspectDatabaseExtensions = inspectDatabaseExtensions;
-  exports.explodeManifest = explodeManifest;
-  exports.initDatabase = initDatabase;
-  exports.sendToDatabase = sendToDatabase;
-  exports.unregister = unregister;
-}());
index 7a6ec62..77ffc44 100644 (file)
@@ -201,14 +201,14 @@ 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 {
+          } 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) {
               stringCallback(null, {
@@ -217,7 +217,7 @@ if (typeof XT === 'undefined') {
                 target: target
               });
             });
-         };
+         }
         };
         async.map(stringsArray, processString, function (err, strings) {
           extensionCallback(null, {
@@ -262,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();
@@ -299,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 e54412d..b82f1bd 100644 (file)
@@ -1,5 +1,5 @@
 <package id        = "distribution-install-460"
-         version   = "4.6.0"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
@@ -19,8 +19,8 @@
 
   <prerequisite type = "query"
                 name = "Checking for too-new xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.6.1';</query>
-    <message>This package may not be applied to a database newer than 4.6.0.
+    <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 36cca32..9ff6ab6 100644 (file)
@@ -1,5 +1,5 @@
 <package id        = "distribution-upgrade-460"
-         version   = "4.6.0"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
@@ -19,8 +19,8 @@
 
   <prerequisite type = "query"
                 name = "Checking for too-new xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.6.1';</query>
-    <message>This package may not be applied to a database newer than 4.6.0.
+    <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 fd4a154..041993b 100644 (file)
@@ -1,5 +1,5 @@
 <package id        = "postbooks-upgrade-460"
-         version   = "4.6.0"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
@@ -19,8 +19,8 @@
 
   <prerequisite type = "query"
                 name = "Checking for too-new xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.6.1';</query>
-    <message>This package may not be applied to a database newer than 4.6.0.
+    <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 1643c2c..b6eb595 100644 (file)
@@ -1,5 +1,5 @@
 <package id        = "manufacturing-install-460"
-         version   = "4.6.0"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
@@ -19,8 +19,8 @@
 
   <prerequisite type = "query"
                 name = "Checking for too-new xTuple ERP database version" >
-    <query>SELECT NOT fetchMetricText('ServerVersion') >= '4.6.1';</query>
-    <message>This package may not be applied to a database newer than 4.6.0.
+    <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 9f4ec08..ff787b4 100644 (file)
@@ -1,5 +1,5 @@
 <package id        = "manufacturing-upgrade-460"
-         version   = "4.6.0"
+         version   = "4.7.0Beta"
          developer = "xTuple"
          descrip   = "load PostBooks resources"
          updater   = "2.2.4" >
@@ -30,8 +30,8 @@
 
 <prerequisite type = "query"
                name = "Checking for too-new xTuple ERP database version" >
-<query>SELECT NOT fetchMetricText('ServerVersion') >= '4.6.1';</query>
-    <message>This package may not be applied to a database newer than 4.6.0.
+<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 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 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 cf880fc..71f410c 100644 (file)
 
       });
       afterEach(function (done) {
-        this.timeout(10 * 1000);
+        this.timeout(30 * 1000);
 
         // restore permissions
         _.extend(XT.session.privileges.attributes, originalPrivileges);
index 3f1548e..43406d3 100644 (file)
@@ -44,7 +44,8 @@
       });
     };
 
-  describe('Sales Order Workspace', function () {
+  // TODO: move to sales order spec
+  describe.skip('Sales Order Workspace', function () {
     this.timeout(30 * 1000);
 
     //
           moduleContainer = XT.app.$.postbooks;
 
         /** Open the first model's salesOrderLineWorkspace...
-            Copied from gridBox buttonTapped function (expandGridRowButton) 
+            Copied from gridBox buttonTapped function (expandGridRowButton)
         */
         lineItemBox.doChildWorkspace({
           workspace: lineItemBox.getWorkspace(),
           index: lineItemBox.getValue().indexOf(model)
         });
 
-        /** The line item's workspace model has been deleted (DESTROYED_CLEAN). 
+        /** The line item's workspace model has been deleted (DESTROYED_CLEAN).
             Client is now in SalesOrderWorkspace.
         */
         var statusChanged = function () {
 
         model.once("status:DESTROYED_CLEAN", statusChanged);
 
-        // Function to keep checking for notifyPopup showing and then tap yes. 
+        // 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; }
index e3c4704..7f95c00 100644 (file)
@@ -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 271eaf3..1662994 100644 (file)
 
   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;
     });
     _.each(spec.afterSaveUIActions || [], function (spec) {
       it(spec.it, function (done) {
-        this.timeout(20 * 1000);
+        this.timeout(60 * 1000);
         spec.action(workspace, done);
       });
     });
       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 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)
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;
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
+}());