Browse files

Merge pull request #59 from xtuple/master

catching up
  • Loading branch information...
2 parents d7d0421 + 7a002e8 commit 00fa3589e6d36f16a3073fc8f0e205f6f4862efe @mikerodonnell89 committed Apr 4, 2013
Showing with 949 additions and 4,394 deletions.
  1. +1 −0 .gitignore
  2. 0 enyo-client/application/debug.html
  3. 0 enyo-client/application/index.html
  4. +1 −0 enyo-client/application/source/en/strings.js
  5. 0 enyo-client/application/source/ext/datasource.js
  6. +17 −16 enyo-client/application/source/models/quote.js
  7. 0 enyo-client/application/source/package.js
  8. 0 enyo-client/application/source/preliminaries.js
  9. +29 −0 enyo-client/application/source/views/list.js
  10. +75 −0 enyo-client/application/source/views/list_relations.js
  11. +39 −0 enyo-client/application/source/views/list_relations_box.js
  12. +31 −3 enyo-client/application/source/views/workspace.js
  13. +1 −0 enyo-client/application/source/widgets/parameter.js
  14. 0 enyo-client/database/orm/models/account.json
  15. 0 enyo-client/database/orm/models/address.json
  16. 0 enyo-client/database/orm/models/characteristic.json
  17. 0 enyo-client/database/orm/models/comment.json
  18. 0 enyo-client/database/orm/models/contact.json
  19. 0 enyo-client/database/orm/models/customer.json
  20. 0 enyo-client/database/orm/models/employee.json
  21. 0 enyo-client/database/orm/models/incident.json
  22. 0 enyo-client/database/orm/models/item.json
  23. 0 enyo-client/database/orm/models/opportunity.json
  24. 0 enyo-client/database/orm/models/project.json
  25. 0 enyo-client/database/orm/models/prospect.json
  26. +9 −3 enyo-client/database/orm/models/quote.json
  27. 0 enyo-client/database/orm/models/to_do.json
  28. 0 enyo-client/database/orm/models/user_account.json
  29. 0 enyo-client/database/source/public/functions/geteffectivextuser.sql
  30. 0 enyo-client/extensions/.gitmodules
  31. 0 enyo-client/extensions/source/admin/client/models/models.js
  32. +8 −0 enyo-client/extensions/source/crm/database/orm/ext/crm.json
  33. 0 enyo-client/extensions/source/incident_plus/database/orm/models/project.json
  34. +1 −0 enyo-client/extensions/source/sales/client/en/strings.js
  35. +2 −1 enyo-client/extensions/source/sales/client/postbooks.js
  36. +10 −0 enyo-client/extensions/source/sales/client/views/workspace.js
  37. 0 enyo-client/extensions/source/sales/database/orm/ext/account.json
  38. 0 enyo-client/extensions/source/sales/database/orm/ext/contact.json
  39. 0 enyo-client/extensions/source/sales/database/orm/ext/incident.json
  40. 0 enyo-client/extensions/source/sales/database/orm/ext/item.json
  41. 0 enyo-client/extensions/source/sales/database/orm/ext/item_site.json
  42. 0 enyo-client/extensions/source/sales/database/orm/ext/opportunity.json
  43. 0 enyo-client/extensions/source/sales/database/orm/ext/project.json
  44. +60 −1 enyo-client/extensions/source/sales/database/orm/ext/quote.json
  45. 0 enyo-client/extensions/source/sales/database/orm/ext/to_do.json
  46. +4 −24 lib/backbone-x/package.json
  47. +0 −1 lib/backbone-x/source/model.js
  48. +0 −5 lib/backbone-x/source/model_mixin.js
  49. 0 lib/backbone-x/source/package.js
  50. 0 lib/backbone-x/source/simple_model.js
  51. +10 −3 lib/enyo-x/source/views/list_relations_box.js
  52. +0 −18 lib/orm/package.json
  53. 0 lib/orm/source/xt/functions/add_column.sql
  54. 0 lib/orm/source/xt/functions/commit_record.sql
  55. 0 lib/orm/source/xt/functions/dispatch.sql
  56. 0 lib/orm/source/xt/functions/fetch.sql
  57. 0 lib/orm/source/xt/functions/retrieve_record.sql
  58. 0 lib/tools/source/session.js
  59. +1 −1 node-datasource/.gitignore
  60. 0 node-datasource/database/orm/models/oauth2.json
  61. +0 −115 node-datasource/database/orm/models/session.json
  62. +17 −4 node-datasource/database/source/init_global.sql
  63. 0 node-datasource/database/source/xt/tables/oa2client.sql
  64. 0 node-datasource/database/source/xt/tables/oa2clientredirs.sql
  65. 0 node-datasource/database/source/xt/tables/oa2token.sql
  66. +1 −11 node-datasource/database/source/xt/tables/session.sql
  67. +1 −7 node-datasource/database/source/xt/tables/sessionorg.sql
  68. 0 node-datasource/database/source/xt/tables/sessionstore.sql
  69. +28 −3 node-datasource/installer/installer.js
  70. +30 −10 node-datasource/installer/orm.js
  71. +0 −96 node-datasource/lib/ext/administrative_route.js
  72. +43 −35 node-datasource/lib/ext/database.js
  73. +139 −0 node-datasource/lib/ext/datasource.js
  74. +8 −12 node-datasource/lib/ext/models.js
  75. +51 −0 node-datasource/lib/ext/pgworker.js
  76. +0 −75 node-datasource/lib/ext/router.js
  77. +0 −413 node-datasource/lib/ext/session.js
  78. +0 −129 node-datasource/lib/functors/changePassword.js
  79. +0 −45 node-datasource/lib/functors/commit.js
  80. +0 −30 node-datasource/lib/functors/dispatch.js
  81. +0 −48 node-datasource/lib/functors/email.js
  82. +0 −47 node-datasource/lib/functors/extensions.js
  83. +0 −35 node-datasource/lib/functors/fetch.js
  84. +0 −30 node-datasource/lib/functors/logout.js
  85. +0 −100 node-datasource/lib/functors/resetPassword.js
  86. +0 −33 node-datasource/lib/functors/retrieve.js
  87. +0 −57 node-datasource/lib/functors/session.js
  88. +0 −69 node-datasource/lib/functors/syncUser.js
  89. +0 −1 node-datasource/lib/key.txt
  90. +14 −9 node-datasource/lib/options.js
  91. +0 −2 node-datasource/lib/private/.gitignore
  92. +0 −1 node-datasource/lib/private/salt.txt
  93. +0 −52 node-datasource/lib/register_service.js
  94. +0 −32 node-datasource/lib/routers/data.js
  95. +0 −12 node-datasource/lib/routers/lookup_router.js
  96. +0 −140 node-datasource/lib/routes/auth.js
  97. +0 −40 node-datasource/lib/routes/data.js
  98. +0 −71 node-datasource/lib/routes/dataFromKey.js
  99. +0 −17 node-datasource/lib/routes/database.js
  100. +0 −93 node-datasource/lib/routes/datasource.js
  101. +0 −225 node-datasource/lib/routes/export.js
  102. +0 −138 node-datasource/lib/routes/file.js
  103. +0 −309 node-datasource/lib/routes/maintenance.js
  104. +0 −113 node-datasource/lib/routes/oauth2auth.js
  105. +0 −57 node-datasource/lib/routes/oauth2token.js
  106. +0 −17 node-datasource/lib/routes/organization.js
  107. +0 −18 node-datasource/lib/routes/redirector.js
  108. +0 −146 node-datasource/lib/routes/report.js
  109. +0 −118 node-datasource/lib/routes/selection.js
  110. +0 −54 node-datasource/lib/routes/session.js
  111. +0 −174 node-datasource/lib/servers/dataserver.js
  112. +0 −7 node-datasource/lib/servers/find_servers.js
  113. +0 −3 node-datasource/lib/servers/package.json
  114. +0 −21 node-datasource/lib/servers/redirector.js
  115. +0 −27 node-datasource/lib/servers/smtpTransport.js
  116. +0 −23 node-datasource/lib/servers/unexposed.js
  117. +0 −12 node-datasource/lib/xt/runtime/devui.js
  118. +0 −30 node-datasource/lib/xt/server/functors/dispatch.js
  119. +15 −23 node-datasource/main.js
  120. 0 node-datasource/oauth2/db/accesstokens.js
  121. 0 node-datasource/oauth2/db/authorizationcodes.js
  122. 0 node-datasource/oauth2/db/clients.js
  123. +1 −1 node-datasource/oauth2/db/connect-xt-pg.js
  124. 0 node-datasource/oauth2/db/index.js
  125. 0 node-datasource/oauth2/db/users.js
  126. +5 −4 node-datasource/oauth2/oauth2.js
  127. +3 −2 node-datasource/oauth2/passport.js
  128. 0 node-datasource/oauth2/user.js
  129. 0 node-datasource/oauth2/utils.js
  130. 0 node-datasource/routes/auth.js
  131. 0 node-datasource/routes/data.js
  132. 0 node-datasource/routes/email.js
  133. +10 −7 node-datasource/routes/extensions.js
  134. 0 node-datasource/routes/file.js
  135. +12 −12 node-datasource/routes/maintenance.js
  136. 0 node-datasource/routes/redirector.js
  137. 0 node-datasource/routes/resetPassword.js
  138. +2 −3 node-datasource/routes/syncUser.js
  139. 0 node-datasource/runMaintenance.js
  140. +4 −11 node-datasource/sample_config.js
  141. +26 −2 node-datasource/test/selenium/environments.js
  142. +7 −6 node-datasource/test/selenium/lib/contactData.js
  143. +2 −1 node-datasource/test/selenium/lib/contactObj.js
  144. +19 −13 node-datasource/test/selenium/lib/createContactForAndroid.js
  145. +15 −3 node-datasource/test/selenium/lib/createContactForFFnC.js
  146. +41 −20 node-datasource/test/selenium/lib/createContactForFFonWin8.js
  147. +15 −9 node-datasource/test/selenium/lib/createContactForIphone.js
  148. +19 −23 node-datasource/test/selenium/lib/login.js
  149. +4 −2 node-datasource/test/selenium/lib/readContactForAndroid.js
  150. +10 −6 node-datasource/test/selenium/lib/readContactForFFnC.js
  151. +14 −11 node-datasource/test/selenium/lib/readContactForFFonWin8.js
  152. +73 −31 node-datasource/test/selenium/runtests.js
  153. 0 node-datasource/views/account.ejs
  154. 0 node-datasource/views/dialog.ejs
  155. 0 node-datasource/views/layout.ejs
  156. 0 node-datasource/views/login.ejs
  157. 0 node-datasource/views/login/assets/favicon.ico
  158. 0 node-datasource/views/login/assets/logo.png
  159. 0 node-datasource/views/login/assets/you-shall-not-pass.png
  160. 0 node-datasource/views/login/stylesheets/ie.css
  161. 0 node-datasource/views/login/stylesheets/print.css
  162. 0 node-datasource/views/login/stylesheets/screen.css
  163. 0 node-datasource/views/scope.ejs
  164. +4 −43 node-datasource/xt/database/database.js
  165. +0 −2 node-datasource/xt/foundation/foundation.js
  166. +4 −27 node-datasource/xt/package.json
  167. +0 −55 node-datasource/xt/server/ext/functor.js
  168. +0 −201 node-datasource/xt/server/ext/response.js
  169. +0 −68 node-datasource/xt/server/ext/route.js
  170. +0 −147 node-datasource/xt/server/ext/router.js
  171. +0 −1 node-datasource/xt/server/package.json
  172. +0 −207 node-datasource/xt/server/server.js
  173. 0 node-datasource/xt/test/test.js
  174. +0 −1 node-datasource/xt/xt.js
  175. +8 −7 {node-datasource → }/package.json
  176. +5 −3 update.sh
View
1 .gitignore
@@ -1,4 +1,5 @@
*.DS_Store
*.swp
*.swo
+node_modules
npm-debug.log
View
0 enyo-client/application/debug.html 100755 → 100644
File mode changed.
View
0 enyo-client/application/index.html 100755 → 100644
File mode changed.
View
1 enyo-client/application/source/en/strings.js
@@ -140,6 +140,7 @@ var lang = XT.stringsFor("en_US", {
"_custPrice": "Cust. Price",
"_customer": "Customer",
"_customerType": "Customer Type",
+ "_customerTypes": "Customer Types",
"_customerPrice": "Customer Price",
"_customers": "Customers",
"_customerProspect": "Customer / Prospect",
View
0 enyo-client/application/source/ext/datasource.js 100755 → 100644
File mode changed.
View
33 enyo-client/application/source/models/quote.js
@@ -134,7 +134,7 @@ white:true*/
// ..........................................................
// METHODS
//
-
+
applyCustomerSettings: function () {
var customer = this.get("customer"),
isFreeFormBillto = customer ? customer.get("isFreeFormBillto") : false,
@@ -152,7 +152,7 @@ white:true*/
// Set read only state for free form shipto
this.setReadOnly(this.shiptoAttrArray, !isFreeFormShipto);
},
-
+
bindEvents: function () {
XM.Document.prototype.bindEvents.apply(this, arguments);
var pricePolicy = XT.session.settings.get("soPriceEffective");
@@ -295,7 +295,7 @@ white:true*/
that.off('change:freight', that.freightDidChange);
that.set("freight", freight);
that.on('change:freight', that.freightDidChange);
-
+
// Now calculate tax
that.calculateFreightTax();
}
@@ -508,15 +508,16 @@ white:true*/
unsetBilltoContact();
}
},
-
+
/**
Fetch selling units of measure after a regular fetch
and also silence `add` and `remove` events.
*/
fetch: function (options) {
+ options = options ? _.clone(options) : {};
+
var that = this,
success = options.success;
- options = options ? _.clone(options) : {};
this.off('add:lineItems remove:lineItems', this.lineItemsDidChange);
this.off('add:lineItems remove:lineItems', this.calculateTotals);
options.success = function (model, resp, options) {
@@ -777,7 +778,7 @@ white:true*/
lineItems = this.get("lineItems"),
params = {},
error;
-
+
error = XM.Document.prototype.validate.apply(this, arguments);
if (error) { return error; }
@@ -884,7 +885,7 @@ white:true*/
}
});
-
+
// ..........................................................
// CLASS METHODS
//
@@ -941,7 +942,7 @@ white:true*/
scheduleDate: allowASAP ? new Date() : undefined
};
},
-
+
bindEvents: function (attributes, options) {
XM.Model.prototype.bindEvents.apply(this, arguments);
var settings = XT.session.settings;
@@ -1269,7 +1270,7 @@ white:true*/
var unit = XM.units.get(id);
that.sellingUnits.add(unit);
});
-
+
// Set the item default selections
if (resetDefaults) {
that.set({
@@ -1388,7 +1389,7 @@ white:true*/
}
return asOf;
},
-
+
priceDidChange: function () {
this.calculateExtendedPrice();
this.calculatePercentages();
@@ -1421,7 +1422,7 @@ white:true*/
item.unitToUnitRatio(priceUnit, inventoryUnit, options);
}
},
-
+
quantityDidChange: function () {
this.calculatePrice();
this.recalculateParent();
@@ -1583,7 +1584,7 @@ white:true*/
setPrice = function () {
// Allow editing again if we could before
that.setReadOnly("price", readOnlyCache);
-
+
// If price was requested before this response,
// then bail out and start over
if (that._invalidPriceRequest) {
@@ -1592,7 +1593,7 @@ white:true*/
that._calculatePrice();
return;
}
-
+
var totalPrice = XT.math.add(prices, XT.SALES_PRICE_SCALE);
that.set("customerPrice", totalPrice);
if (that._updatePrice) {
@@ -1606,7 +1607,7 @@ white:true*/
parentDate = parent.get(parent.documentDateKey);
customer = parent.get("customer");
currency = parent.get("currency");
-
+
// If we already have a request pending we need to indicate
// when that is done to start over because something has changed.
if (this._pendingPriceRequest) {
@@ -1850,7 +1851,7 @@ white:true*/
recordType: 'XM.QuoteListItem',
editableModel: 'XM.Quote',
-
+
/**
Returns quote status as a localized string.
@@ -1863,7 +1864,7 @@ white:true*/
}
});
-
+
// Add in quote mixin
XM.QuoteListItem = XM.QuoteListItem.extend(XM.QuoteMixin);
View
0 enyo-client/application/source/package.js 100755 → 100644
File mode changed.
View
0 enyo-client/application/source/preliminaries.js 100755 → 100644
File mode changed.
View
29 enyo-client/application/source/views/list.js
@@ -382,6 +382,35 @@ trailing:true white:true*/
]
});
XV.registerModelList("XM.CustomerShiptoRelation", "XV.CustomerShiptoList");
+
+ // ..........................................................
+ // CUSTOMER TYPE LIST
+ //
+
+ enyo.kind({
+ name: "XV.CustomerTypeList",
+ kind: "XV.List",
+ label: "_customerTypes".loc(),
+ collection: "XM.CustomerTypeCollection",
+ query: {orderBy: [
+ {attribute: 'code'}
+ ]},
+ components: [
+ {kind: "XV.ListItem", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListColumn", classes: "short",
+ components: [
+ {kind: "XV.ListAttr", attr: "code", isKey: true}
+ ]},
+ {kind: "XV.ListColumn", classes: "last", fit: true, components: [
+ {kind: "XV.ListAttr", attr: "description"}
+ ]}
+ ]}
+ ]}
+ ]
+ });
+
+ XV.registerModelList("XM.CustomerType", "XV.CustomerTypeList");
// ..........................................................
// EMPLOYEE
View
75 enyo-client/application/source/views/list_relations.js
@@ -298,6 +298,81 @@ trailing:true white:true*/
});
// ..........................................................
+ // OPPORTUNITY QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.OpportunityQuoteListRelations",
+ kind: "XV.ListRelations",
+ orderBy: [
+ {attribute: 'id', descending: true}
+ ],
+ parentKey: "opportunity",
+ components: [
+ {kind: "XV.ListItem", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListColumn", classes: "first", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListAttr", attr: "number", classes: "bold"},
+ {kind: "XV.ListAttr", attr: "shipVia", classes: "right"}
+ ]}
+ ]}
+ ]}
+ ]}
+ ]
+ });
+
+ // ..........................................................
+ // CUSTOMER QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.CustomerQuoteListRelations",
+ kind: "XV.ListRelations",
+ orderBy: [
+ {attribute: 'id', descending: true}
+ ],
+ parentKey: "customer",
+ components: [
+ {kind: "XV.ListItem", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListColumn", classes: "first", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListAttr", attr: "number", classes: "bold"},
+ {kind: "XV.ListAttr", attr: "shipVia", classes: "right"}
+ ]}
+ ]}
+ ]}
+ ]}
+ ]
+ });
+
+ // ..........................................................
+ // PROSPECT QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.ProspectQuoteListRelations",
+ kind: "XV.ListRelations",
+ orderBy: [
+ {attribute: 'id', descending: true}
+ ],
+ parentKey: "customer",
+ components: [
+ {kind: "XV.ListItem", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListColumn", classes: "first", components: [
+ {kind: "FittableColumns", components: [
+ {kind: "XV.ListAttr", attr: "number", classes: "bold"},
+ {kind: "XV.ListAttr", attr: "shipVia", classes: "right"}
+ ]}
+ ]}
+ ]}
+ ]}
+ ]
+ });
+
+ // ..........................................................
// QUOTE LINE ITEM
//
View
39 enyo-client/application/source/views/list_relations_box.js
@@ -31,4 +31,43 @@ trailing:true white:true*/
canOpen: false
});
+ // ..........................................................
+ // OPPORTUNITY QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.OpportunityQuoteListRelationsBox",
+ kind: "XV.ListRelationsBox",
+ title: "_quotes".loc(),
+ parentKey: "opportunity",
+ listRelations: "XV.OpportunityQuoteListRelations",
+ searchList: "XV.QuoteList"
+ });
+
+ // ..........................................................
+ // CUSTOMER QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.CustomerQuoteListRelationsBox",
+ kind: "XV.ListRelationsBox",
+ title: "_quotes".loc(),
+ parentKey: "customer",
+ listRelations: "XV.CustomerQuoteListRelations",
+ searchList: "XV.QuoteList"
+ });
+
+ // ..........................................................
+ // PROSPECT QUOTE
+ //
+
+ enyo.kind({
+ name: "XV.ProspectQuoteListRelationsBox",
+ kind: "XV.ListRelationsBox",
+ title: "_quotes".loc(),
+ parentKey: "customer",
+ listRelations: "XV.ProspectQuoteListRelations",
+ searchList: "XV.QuoteList"
+ });
+
}());
View
34 enyo-client/application/source/views/workspace.js
@@ -504,6 +504,7 @@ trailing:true white:true*/
{kind: "XV.TaxZonePicker", attr: "taxZone", label: "_defaultTaxZone".loc()}
]}
]},
+ {kind: "XV.CustomerQuoteListRelationsBox", attr: "quoteRelations"},
{kind: "XV.CustomerShipToBox", attr: "shiptos"},
{kind: "XV.CustomerCommentBox", attr: "comments"},
{kind: "XV.TaxRegistrationBox", attr: "taxRegistration"},
@@ -568,6 +569,32 @@ trailing:true white:true*/
XV.registerModelWorkspace("XM.CustomerRelation", "XV.CustomerWorkspace");
XV.registerModelWorkspace("XM.CustomerListItem", "XV.CustomerWorkspace");
XV.registerModelWorkspace("XM.CustomerProspectListItem", "XV.CustomerWorkspace");
+
+ // ..........................................................
+ // CUSTOMER TYPE
+ //
+
+ enyo.kind({
+ name: "XV.CustomerTypeWorkspace",
+ kind: "XV.Workspace",
+ title: "_customerType".loc(),
+ model: "XM.CustomerType",
+ components: [
+ {kind: "Panels", arrangerKind: "CarouselArranger",
+ fit: true, components: [
+ {kind: "XV.Groupbox", name: "mainPanel", components: [
+ {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
+ {kind: "XV.ScrollableGroupbox", name: "mainGroup",
+ classes: "in-panel", components: [
+ {kind: "XV.InputWidget", attr: "code"},
+ {kind: "XV.InputWidget", attr: "description"}
+ ]}
+ ]}
+ ]}
+ ]
+ });
+
+ XV.registerModelWorkspace("XM.CustomerType", "XV.CustomerTypeWorkspace");
// ..........................................................
// FILE
@@ -821,6 +848,7 @@ trailing:true white:true*/
{kind: "XV.ProductCategoryPicker", attr: "productCategory",
label: "_category".loc()},
{kind: "XV.SalesPriceWidget", attr: "listPrice"},
+ {kind: "XV.CostWidget", attr: "listCost"},
{kind: "XV.UnitPicker", attr: "priceUnit"},
{kind: "XV.ItemCharacteristicsWidget", attr: "characteristics"},
{kind: "onyx.GroupboxHeader",
@@ -1178,10 +1206,10 @@ trailing:true white:true*/
{kind: "XV.ContactWidget", attr: "contact",
showAddress: true, label: "_name".loc()},
{kind: "onyx.GroupboxHeader", content: "_notes".loc()},
- {kind: "XV.TextArea", attr: "notes"}//,
- //{kind: "onyx.GroupboxHeader", content: "_quotes".loc()}
+ {kind: "XV.TextArea", attr: "notes"}
]}
- ]}
+ ]},
+ {kind: "XV.ProspectQuoteListRelationsBox", attr: "quoteRelations"}
]},
{kind: "onyx.Popup", name: "findExistingAccountPopup", centered: true,
modal: true, floating: true, scrim: true, onShow: "popupShown",
View
1 enyo-client/application/source/widgets/parameter.js
@@ -193,6 +193,7 @@ trailing:true white:true*/
{name: "name", label: "_name".loc(), attr: "name"}
]
});
+
// ..........................................................
// FILE
//
View
0 enyo-client/database/orm/models/account.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/address.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/characteristic.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/comment.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/contact.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/customer.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/employee.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/incident.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/item.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/opportunity.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/project.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/prospect.json 100755 → 100644
File mode changed.
View
12 enyo-client/database/orm/models/quote.json
@@ -1382,10 +1382,16 @@
}
},
{
+ "name": "number",
+ "attr": {
+ "type": "String",
+ "column": "quhead_number"
+ }
+ },
+ {
"name": "customer",
- "toOne": {
- "isNested": true,
- "type": "CustomerProspectRelation",
+ "attr": {
+ "type": "Number",
"column": "quhead_cust_id"
}
},
View
0 enyo-client/database/orm/models/to_do.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/orm/models/user_account.json 100755 → 100644
File mode changed.
View
0 enyo-client/database/source/public/functions/geteffectivextuser.sql 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/.gitmodules 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/admin/client/models/models.js 100755 → 100644
File mode changed.
View
8 enyo-client/extensions/source/crm/database/orm/ext/crm.json
@@ -384,6 +384,14 @@
"column": "ophead_id",
"inverse": "opportunity"
}
+ },
+ {
+ "name": "quoteRelations",
+ "toMany": {
+ "type": "QuoteRelation",
+ "column": "ophead_id",
+ "inverse": "opportunity"
+ }
}
],
"sequence": 0,
View
0 enyo-client/extensions/source/incident_plus/database/orm/models/project.json 100755 → 100644
File mode changed.
View
1 enyo-client/extensions/source/sales/client/en/strings.js
@@ -22,6 +22,7 @@ var lang = XT.stringsFor("en_US", {
"_autoAllocateCreditMemos": "Allocate Credit Memos to New Sales Order on Save",
"_autoSelectForBilling": "Check 'Select for Billing' option on Ship Order",
"_customerDefaults": "Customer Defaults",
+ "_customerTypes": "Customer Types",
"_creditControl": "Credit Control",
"_creditMemo": "Credit Memo",
"_current": "Current",
View
3 enyo-client/extensions/source/sales/client/postbooks.js
@@ -21,7 +21,8 @@ trailing:true white:true*/
{name: "siteTypeList", kind: "XV.SiteTypeList"},
{name: "itemSiteList", kind: "XV.ItemSiteList"},
{name: "costCategoryList", kind: "XV.CostCategoryList"},
- {name: "plannerCodeList", kind: "XV.PlannerCodeList"}
+ {name: "plannerCodeList", kind: "XV.PlannerCodeList"},
+ {name: "customerTypeList", kind: "XV.CustomerTypeList"}
];
XT.app.$.postbooks.appendPanels("setup", panels);
View
10 enyo-client/extensions/source/sales/client/views/workspace.js
@@ -6,6 +6,7 @@ trailing:true white:true*/
(function () {
XT.extensions.sales.initWorkspaces = function () {
+ var extensions;
// ..........................................................
// ACCOUNT
@@ -160,6 +161,15 @@ trailing:true white:true*/
]
});
+ // ..........................................................
+ // INCIDENT
+ //
+
+ extensions = [
+ {kind: "XV.OpportunityQuoteListRelationsBox", container: "panels", attr: "quoteRelations"}
+ ];
+
+ XV.appendExtension("XV.OpportunityWorkspace", extensions);
};
View
0 enyo-client/extensions/source/sales/database/orm/ext/account.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/contact.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/incident.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/item.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/item_site.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/opportunity.json 100755 → 100644
File mode changed.
View
0 enyo-client/extensions/source/sales/database/orm/ext/project.json 100755 → 100644
File mode changed.
View
61 enyo-client/extensions/source/sales/database/orm/ext/quote.json
@@ -21,6 +21,39 @@
"column": "quhead_id",
"inverse": "source"
}
+ },
+ {
+ "name": "opportunity",
+ "toOne": {
+ "isNested": true,
+ "type": "OpportunityRelation",
+ "column": "quhead_ophead_id"
+ }
+ }
+ ],
+ "sequence": 0,
+ "isSystem": true
+ },
+ {
+ "context": "sales",
+ "nameSpace": "XM",
+ "type": "QuoteListItem",
+ "table": "xt.quheadinfo",
+ "isExtension": true,
+ "comment": "Extended by Sales",
+ "relations": [
+ {
+ "column": "quhead_id",
+ "inverse": "id"
+ }
+ ],
+ "properties": [
+ {
+ "name": "opportunity",
+ "attr": {
+ "type": "Number",
+ "column": "quhead_ophead_id"
+ }
}
],
"sequence": 0,
@@ -77,5 +110,31 @@
],
"sequence": 0,
"isSystem": true
+ },
+ {
+ "context": "sales",
+ "nameSpace": "XM",
+ "type": "Customer",
+ "table": "custinfo",
+ "isExtension": true,
+ "comment": "Extended by Sales",
+ "relations": [
+ {
+ "column": "cust_id",
+ "inverse": "id"
+ }
+ ],
+ "properties": [
+ {
+ "name": "quoteRelations",
+ "toMany": {
+ "type": "QuoteRelation",
+ "column": "cust_id",
+ "inverse": "customer"
+ }
+ }
+ ],
+ "sequence": 0,
+ "isSystem": true
}
-]
+]
View
0 enyo-client/extensions/source/sales/database/orm/ext/to_do.json 100755 → 100644
File mode changed.
View
28 lib/backbone-x/package.json 100755 → 100644
@@ -1,24 +1,4 @@
-{
- "author": "John Rogelstad <john@xtuple.com>",
- "name": "backbone-x",
- "description": "Model framework for xTuple",
- "version": "1.4.0",
- "repository": {
- "type": "git",
- "url": "https://github.com/xtuple/backbone-x.git"
- },
- "dependencies": {},
- "devDependencies": {},
- "optionalDependencies": {},
- "engines": {
- "node": "*"
- },
- "main": "source/package.js",
- "dependencies": {
- "backbone":"0.9.2",
- "backbone-relational":"0.6.x",
- "underscore":"1.4.x",
- "vows":"0.7.0"
- },
- "scripts": {}
-}
+{
+ "name": "backbone-x",
+ "main": "source/package.js"
+}
View
1 lib/backbone-x/source/model.js 100755 → 100644
@@ -56,7 +56,6 @@ white:true*/
this.on('change', this.didChange);
this.on('error', this.didError);
this.on('destroy', this.didDestroy);
- this.on('change:lock', this.lockDidChangeTest);
for (i = 0; i < relations.length; i++) {
if (relations[i].type === Backbone.HasMany &&
relations[i].includeInJSON === true) {
View
5 lib/backbone-x/source/model_mixin.js
@@ -132,14 +132,9 @@ white:true*/
this.on('change', this.didChange);
this.on('error', this.didError);
this.on('destroy', this.didDestroy);
- this.on('change:lock', this.lockDidChangeTest);
this._eventsBound = true;
},
- lockDidChangeTest: function () {
- console.log("I'm predicting that this won't ever happen: lockDidChangeTest");
- },
-
/**
Returns whether the current record can be updated based on privilege
settings.
View
0 lib/backbone-x/source/package.js 100755 → 100644
File mode changed.
View
0 lib/backbone-x/source/simple_model.js 100755 → 100644
File mode changed.
View
13 lib/enyo-x/source/views/list_relations_box.js
@@ -114,9 +114,16 @@ trailing:true white:true, bitwise:false*/
// of the item that we've just selected, as selectedModel refers
// to an info model, which is not the type of model we want
// to use in the list
- var Klass = XT.getObjectByName(selectedModel.editableModel),
- model = Klass.findOrCreate({id: selectedModel.id}),
- InfoKlass = model.getRelation(key).relatedModel,
+ var Klass = XT.getObjectByName(selectedModel.editableModel);
+ var model = Klass.findOrCreate({id: selectedModel.id});
+ if (!model.getRelation(key)) {
+ XT.log("Model", model.recordType, "has no relation", key,
+ ". It's likely that the property is on the list relation",
+ "but not the editable orm, or you have it as a number",
+ "in the editable orm instead of a nested object");
+ }
+
+ var InfoKlass = model.getRelation(key).relatedModel,
infoModel = InfoKlass.findOrCreate({id: parent.get(attr)}),
listModel = ListModel.findOrCreate({id : selectedModel.id}),
setAndSave = function () {
View
18 lib/orm/package.json
@@ -1,18 +0,0 @@
-{
- "author": "John Rogelstad <jrogelstad@xtuple.com>",
- "name": "orm",
- "description": "Postgres foundation for xTuple",
- "version": "1.0.0-beta",
- "repository": {
- "type": "git",
- "url": "https://github.com/xtuple/orm.git"
- },
- "dependencies": {
- "xt":"git://github.com/xtuple/node-xt.git"
- },
- "devDependencies": {},
- "optionalDependencies": {},
- "engines": {
- "node": "*"
- }
-}
View
0 lib/orm/source/xt/functions/add_column.sql 100755 → 100644
File mode changed.
View
0 lib/orm/source/xt/functions/commit_record.sql 100755 → 100644
File mode changed.
View
0 lib/orm/source/xt/functions/dispatch.sql 100755 → 100644
File mode changed.
View
0 lib/orm/source/xt/functions/fetch.sql 100755 → 100644
File mode changed.
View
0 lib/orm/source/xt/functions/retrieve_record.sql 100755 → 100644
File mode changed.
View
0 lib/tools/source/session.js 100755 → 100644
File mode changed.
View
2 node-datasource/.gitignore
@@ -5,6 +5,6 @@ config*
datasource.log
datasource-err.log
www
-lib/private
+lib/private/*
pid/*
test/shared/loginData.js
View
0 node-datasource/database/orm/models/oauth2.json 100755 → 100644
File mode changed.
View
115 node-datasource/database/orm/models/session.json 100755 → 100644
@@ -2,121 +2,6 @@
{
"context": "xtuple",
"nameSpace": "XM",
- "type": "Session",
- "table": "xt.session",
- "comment": "Session Map",
- "properties": [
- {
- "name": "id",
- "attr": {
- "type": "String",
- "column": "session_id"
- }
- },
- {
- "name": "sid",
- "attr": {
- "type": "String",
- "column": "session_sid",
- "isPrimaryKey": true
- }
- },
- {
- "name": "lastModified",
- "attr": {
- "type": "Date",
- "column": "session_updated"
- }
- },
- {
- "name": "created",
- "attr": {
- "type": "Date",
- "column": "session_created"
- }
- },
- {
- "name": "checksum",
- "attr": {
- "type": "String",
- "column": "session_checksum"
- }
- },
- {
- "name": "username",
- "attr": {
- "type": "String",
- "column": "session_username"
- }
- },
- {
- "name": "organizations",
- "toMany": {
- "type": "SessionOrganization",
- "column": "session_sid",
- "inverse": "session"
- }
- },
- {
- "name": "organization",
- "attr": {
- "type": "String",
- "column": "session_org_name"
- }
- },
- {
- "name": "socket",
- "attr": {
- "type": "String",
- "column": "session_socket"
- }
- }
- ],
- "isSystem": true
- },
- {
- "context": "xtuple",
- "nameSpace": "XM",
- "type": "SessionOrganization",
- "table": "xt.sessionorg",
- "idSequenceName": "sessionorg_sessionorg_id_seq",
- "comment": "Session Organization Map",
- "properties": [
- {
- "name": "id",
- "attr": {
- "type": "Number",
- "column": "sessionorg_id",
- "isPrimaryKey": true
- }
- },
- {
- "name": "session",
- "attr": {
- "type": "String",
- "column": "sessionorg_session_sid"
- }
- },
- {
- "name": "username",
- "attr": {
- "type": "String",
- "column": "sessionorg_usr_id"
- }
- },
- {
- "name": "name",
- "attr": {
- "type": "String",
- "column": "sessionorg_org_name"
- }
- }
- ],
- "isSystem": true
- },
- {
- "context": "xtuple",
- "nameSpace": "XM",
"type": "SessionStore",
"table": "xt.sessionstore",
"idSequenceName": "sessionstore_sessionstore_id_seq",
View
21 node-datasource/database/source/init_global.sql 100755 → 100644
@@ -10,20 +10,33 @@
-- [ START ] xt
-- xt tables
-\i xt/tables/bicache.sql
+-- These need to be in the correct order for them to load based on dependant columns.
\i xt/tables/datasource.sql
\i xt/tables/dbserver.sql
\i xt/tables/ext.sql
-\i xt/tables/oa2client.sql
-\i xt/tables/oa2clientredirs.sql
-\i xt/tables/oa2token.sql
\i xt/tables/org.sql
\i xt/tables/orgext.sql
+-- TODO Remove session in a future version after it has had time to be dropped.
\i xt/tables/session.sql
\i xt/tables/sessionorg.sql
+
\i xt/tables/sessionstore.sql
+
\i xt/tables/usr.sql
\i xt/tables/usrorg.sql
+\i xt/tables/sessionorg.sql
+
+\i xt/tables/oa2client.sql
+\i xt/tables/oa2clientredirs.sql
+\i xt/tables/oa2token.sql
+
+\i xt/tables/bicache.sql
+
+\i xt/tables/oa2client.sql
+\i xt/tables/oa2clientredirs.sql
+\i xt/tables/oa2token.sql
+
+\i xt/tables/bicache.sql
-- xt functions
\i xt/functions/add_priv.sql
View
0 node-datasource/database/source/xt/tables/oa2client.sql 100755 → 100644
File mode changed.
View
0 node-datasource/database/source/xt/tables/oa2clientredirs.sql 100755 → 100644
File mode changed.
View
0 node-datasource/database/source/xt/tables/oa2token.sql 100755 → 100644
File mode changed.
View
12 node-datasource/database/source/xt/tables/session.sql
@@ -1,13 +1,3 @@
-- table definition
-select xt.create_table('session');
-select xt.add_column('session','session_id', 'text');
-select xt.add_column('session','session_sid', 'text', 'primary key');
-select xt.add_column('session','session_created', 'bigint');
-select xt.add_column('session','session_updated', 'bigint');
-select xt.add_column('session','session_checksum', 'text');
-select xt.add_column('session','session_org_name', 'text', 'references xt.org (org_name)');
-select xt.add_column('session','session_username', 'text');
-select xt.add_column('session','session_socket', 'text');
-
-comment on table xt.session is 'Sessions';
+DROP TABLE IF EXISTS xt.session CASCADE;
View
8 node-datasource/database/source/xt/tables/sessionorg.sql
@@ -1,9 +1,3 @@
-- table definition
-select xt.create_table('sessionorg');
-select xt.add_column('sessionorg','sessionorg_id', 'serial', 'primary key');
-select xt.add_column('sessionorg','sessionorg_session_sid', 'text', 'references xt.session (session_sid) on delete cascade');
-select xt.add_column('sessionorg','sessionorg_org_name', 'text', 'references xt.org (org_name) on delete cascade');
-select xt.add_column('sessionorg','sessionorg_usr_id', 'text', 'references xt.usr (usr_id) on delete cascade');
-
-comment on table xt.usrorg is 'Defines global user organization assignments to sessions';
+DROP TABLE IF EXISTS xt.sessionorg CASCADE;
View
0 node-datasource/database/source/xt/tables/sessionstore.sql 100755 → 100644
File mode changed.
View
31 node-datasource/installer/installer.js
@@ -1,12 +1,25 @@
#!/usr/bin/env node
/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true */
+/*global X:true, XT:true, _:true */
+
+_ = require("underscore");
+
+require('../xt/foundation/foundation');
+require('../xt/database/database');
+
+if (typeof XT === 'undefined') {
+ XT = {};
+}
+
+if (!X.options) {
+ X.options = {};
+ X.options.datasource = {};
+}
(function () {
"use strict";
- var orm = require('./orm'),
- argv = process.argv,
+ var argv = process.argv,
credentials = {},
path = argv[argv.indexOf("--path") + 1];
@@ -27,5 +40,17 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
credentials.password = "";
}
+ // Use pgWorker.
+ if (argv.indexOf("-w") > -1) {
+ X.log("Using a seperate pgWorker process.");
+ X.options.datasource.pgWorker = true;
+ } else {
+ X.warn("Not using pgWorker process.");
+ X.warn("Use '-w' command line flag to enable it if you want to.");
+ }
+
+ // Require orm after X.options setting.
+ var orm = require('./orm');
+
orm.run(credentials, path);
}());
View
40 node-datasource/installer/orm.js 100755 → 100644
@@ -1,18 +1,36 @@
/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true */
-
-require('../xt/foundation/foundation');
-require('../xt/database/database');
+/*global X:true, XT:true, _:true */
(function () {
"use strict";
- var _path = X.path, _ = X._, _fs = X.fs, initSocket, testConnection, dive,
- parseFile, calculateDependencies, dependenciesFor, checkDependencies, cleanse,
- installQueue, submit, existing, findExisting, install, select, refresh, runOrmInstaller;
-
- X.db = X.Database.create();
+ var _path = X.path,
+ _ = X._,
+ _fs = X.fs,
+ calculateDependencies,
+ checkDependencies,
+ cleanse,
+ dependenciesFor,
+ dive,
+ existing,
+ findExisting,
+ install,
+ installQueue,
+ parseFile,
+ refresh,
+ runOrmInstaller,
+ select,
+ submit,
+ testConnection;
+
+ // When ran from the maintenance route, we already have XT.dataSource.
+ // When ran from the installer, we need to included it after X.options is set.
+ if (typeof XT.dataSource === 'undefined') {
+ require('../lib/ext/datasource');
+ }
+
+ X.db = XT.dataSource;
cleanse = function (orm) {
var ret = _.clone(orm);
@@ -111,7 +129,9 @@ require('../xt/database/database');
// this is the actual callback! The first arg is an error, which is null if
// we've made it this far. The second arg is an array of all the orm names
// that have been installed.
- return ack(null, _.map(socket.installed, function (orm) {return orm.type}));
+ return ack(null, _.map(socket.installed, function (orm) {
+ return orm.type;
+ }));
}
orm = queue.shift();
View
96 node-datasource/lib/ext/administrative_route.js
@@ -1,96 +0,0 @@
-/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
-regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true, XM:true */
-
-(function () {
- "use strict";
-
- //var _ = X._;
-
- /**
- Administrative route
-
- @class
- @extends X.Route
- */
- X.AdministrativeRoute = X.Route.extend(/** @lends X.AdministrativeRoute */{
- /**
- The name of the model that this route will operate on.
-
- @type {String}
- */
- clientModel: "",
-
- /**
- Init. Sets this route to handle /%@ and other paths you get when you hold
- down the shift key and start typing.
- */
- init: function () {
- var model = this.get("clientModel"), handles = [];
- handles.push("/%@/{id}".f(model));
- handles.push("/%@s".f(model));
- handles.push("/%@".f(model));
- this.set("handles", handles);
- this._super.init.call(this);
- },
- /**
- Sends requests to the appropriate function
-
- @param {X.Reponse} xtr
- */
- handle: function (xtr) {
- var method = xtr.get("method"), data = xtr.get("json");
- //X.debug("X.AdministrativeRoute.handle(): ", method);
- if (method === "PUT") this.update.apply(this, arguments);
- else if (method === "DELETE") this.delete.apply(this, arguments);
- else if (method === "POST") {
- //X.debug("METHOD POST: ", data);
- if (data.lookup) {
- delete data.lookup;
- this.lookup(xtr, data);
- } else this.new.apply(this, arguments);
- } else this.fetch.apply(this, arguments);
- },
-
- /**
- Looks up a single record based on specified query.
-
- @param {X.Reponse} xtr
- @param {Object} data
- */
- lookup: function (xtr, data) {
- var Model = this.get("model"),
- Klass = XM.Collection.extend({model: Model}),
- coll = new Klass({model: Model}),
- query = { parameters: [] },
- param = {},
- options = {},
- prop;
- for (prop in data) {
- if (data.hasOwnProperty(prop)) {
- param.attribute = prop;
- param.value = data[prop];
- query.parameters.push(param);
- }
- }
- options.query = query;
- options.success = function (res) {
- if (res.length === 0) {
- X.log("Error: no records found in lookup. Check the privileges for the node user");
- xtr.error({isError: true, reason: "No records found in lookup. Check the privileges for the node user"});
- } else {
- xtr.write(res.models[0].toJSON()).close();
- }
- };
- options.error = function (model, err) {
- xtr.error({isError: true, reason: err.message()});
- };
- // make this request with the authority of the node user
- options.username = X.options.globalDatabase.nodeUsername;
- coll.fetch(options);
- },
-
- className: "X.AdministrativeRoute"
- });
-
-}());
View
78 node-datasource/lib/ext/database.js
@@ -1,51 +1,59 @@
/*jshint node:true, bitwise:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true, issue:true */
+/*global X:true, XM:true, issue:true */
(function () {
"use strict";
- var _ = X._;
-
/**
xt-datasource specific implementation of X.Database. Handles communication with postgres.
@class
@extends X.Database
*/
X.database = X.Database.create(/** @lends X.database */{
- query: function (organization, query, callback) {
- // we have to do a doubly asynchronous lookup (for now)
- // before we can build the correct connection string
- X.router.lookup("organization", {name: organization}, _.bind(
- this.didLookup, this, query, callback, {type: "organization", organization: organization}));
- },
-
- /**
- Lookup callback.
- */
- didLookup: function (query, callback, which, err, res) {
- var options;
- if (err || !res) return callback(err? err: "could not find %@".f(which.type));
- switch (which.type) {
- case "organization":
- X.router.lookup("database", {name: res.databaseServer}, _.bind(
- this.didLookup, this, query, callback, {type: "database", organization: which.organization}));
- break;
- case "database":
- options = {
- user: res.user || "admin",
- hostname: res.hostname,
- port: res.port,
- database: which.organization,
- password: res.password
- };
- this._super.query.call(this, query, options, callback);
- break;
- }
+ query: function (organization, dbQuery, done) {
+ var that = this,
+ orgColl = new XM.OrganizationCollection(),
+ fetchOptions = {};
+
+ fetchOptions.success = function (res) {
+ // We should only get one record back matching the organization.
+ if (res.models.length !== 1) {
+ var message = "Error fetching organization.";
+ X.log(message);
+
+ // No match or multiple which is not allowed. Send nothing.
+ return done(new Error(message));
+ }
+
+ // Get db connection string and make the query.
+ var options = {
+ user: res.models[0].get("databaseServer").user || "admin",
+ hostname: res.models[0].get("databaseServer").hostname,
+ port: res.models[0].get("databaseServer").port,
+ database: organization,
+ password: res.models[0].get("databaseServer").password
+ };
+ XT.dataSource.query(dbQuery, options, done);
+ };
+
+ fetchOptions.error = function (res, err) {
+ if (err.code === 'xt1007') {
+ // XXX should "result not found" really be an error?
+ return done(null, null);
+ } else {
+ var message = "Error fetching organization.";
+ X.log(message);
+ return done(new Error(message));
+ }
+ };
+
+ // Fetch the collection looking for a matching organization.
+ fetchOptions.username = X.options.globalDatabase.nodeUsername;
+ fetchOptions.query = {};
+ fetchOptions.query.parameters = [{attribute: "name", value: organization}];
+ orgColl.fetch(fetchOptions);
}
});
-
- // don't break any existing code...
- X.db = X.database;
}());
View
139 node-datasource/lib/ext/datasource.js
@@ -7,6 +7,145 @@ white:true*/
"use strict";
XT.dataSource = X.Database.create({
+ requestNum: 0,
+ callbacks: {},
+
+ /**
+ * Initializes database by setting the default pool size
+ */
+ init: function () {
+ var that = this;
+
+ // TODO - I don't think the cleanup task is needed when using a child pgworker.
+ // It may not ne needed at all anymore. BT 2013-03-31
+ X.addCleanupTask(_.bind(this.cleanup, this), this);
+ X.pg.defaults.poolSize = this.poolSize;
+
+ if (X.options && X.options.datasource && X.options.datasource.pgWorker) {
+ // Single worker version.
+ this.worker = require('child_process').fork(__dirname + '/pgworker.js');
+ this.worker.on('message', function (m) {
+ var callback = that.callbacks[m.id];
+ delete that.callbacks[m.id];
+
+ if (m.err) {
+ issue(X.warning("Failed to connect to database: " +
+ "{hostname}:{port}/{database} => %@".f(m.options, m.err.message)));
+ return callback(m.err);
+ }
+
+ callback(m.err, m.result);
+ });
+
+ this.worker.on('exit', function (code, signal) {
+ var pid = that.worker.pid,
+ exitCode = that.worker.exitCode,
+ signalCode = that.worker.signalCode;
+
+ X.err('pgWorker ' + pid + ' died (exitCode: ' + exitCode + ' signalCode: ' + signalCode + '). Cannot run any more queries.');
+
+ // TODO - Figure out how to restart the worker. This doesn't work.
+ //that.worker = require('child_process').fork(__dirname + '/pgworker.js');
+ });
+ }
+
+ // NOTE: Round robin benchmarks are slower then the above single pgworker code.
+ // Round robin workers version. This might be useful in the future.
+ // if (require('os').cpus().length > 1) {
+ // this.numWorkers = require('os').cpus().length * 2;
+ // //this.numWorkers = 1;
+ // } else {
+ // this.numWorkers = 1;
+ // }
+
+ // X.log("Number of pgWorkers = ", this.numWorkers);
+
+ // this.nextWorker = 0;
+ // this.workers = [];
+ // for (var i=0; i < this.numWorkers; i++) {
+ // var worker = require('child_process').fork(__dirname + '/pgworker.js');
+ // this.workers.push(worker);
+
+ // worker.on('message', function(m) {
+ // var callback = that.callbacks[m.id];
+ // delete that.callbacks[m.id];
+
+ // if (m.err) {
+ // issue(X.warning("Failed to connect to database: " +
+ // "{hostname}:{port}/{database} => %@".f(m.options, m.err.message)));
+ // return callback(m.err);
+ // }
+
+ // callback(m.err, m.result);
+ // })
+ // }
+ },
+
+ /**
+ Perform query
+
+ @param {String} query
+ @param {Object} options
+ @param {Function} callback
+ */
+ query: function (query, options, callback) {
+ var str = this.conString(_.clone(options));
+
+ if (X.options && X.options.datasource && X.options.datasource.pgWorker) {
+ this.requestNum += 1;
+
+ this.callbacks[this.requestNum] = callback;
+ // Single worker version.
+ this.worker.send({id: this.requestNum, query: query, options: options, conString: str, poolSize: this.poolSize});
+
+ // NOTE: Round robin benchmarks are slower then the above single pgworker code.
+ // Round robin workers version. This might be useful in the future.
+ // var worker = this.workers[this.nextWorker];
+ // this.nextWorker += 1;
+ // if (this.nextWorker === this.workers.length) {
+ // this.nextWorker = 0;
+ // }
+ // worker.send({id: this.requestNum, query: query, options: options, conString: str});
+ } else {
+ X.pg.connect(str, _.bind(this.connected, this, query, options, callback));
+ }
+ },
+
+ /**
+ * Connected.
+ *
+ * NOTE: This is only used when not using a seperate pgWorker process.
+ * It's useful if you need to run the node-inspector debugger which breaks on multiple processes.
+ * See: https://github.com/dannycoates/node-inspector/issues/130
+ * You can also just run, "kill -USR1 12345", to start the debugger on a running process
+ * instead of starting node with the debugger running: "sudo node --debug-brk main.js".
+ */
+ connected: function (query, options, callback, err, client, done, ranInit) {
+ if (err) {
+ issue(X.warning("Failed to connect to database: " +
+ "{hostname}:{port}/{database} => %@".f(options, err.message)));
+ done();
+ return callback(err);
+ }
+
+ if (ranInit === true) {
+ client.hasRunInit = true;
+ }
+
+ if (!client.hasRunInit) {
+ client.query("set plv8.start_proc = \"xt.js_init\";", _.bind(
+ this.connected, this, query, options, callback, err, client, done, true));
+ } else {
+
+ client.query(query, function (err, result) {
+ // Release the client from the pool.
+ done();
+
+ // Call the call back.
+ callback(err, result);
+ });
+ }
+ },
/*
Returns a record array based on a query.
View
20 node-datasource/lib/ext/models.js 100755 → 100644
@@ -9,10 +9,9 @@ white:true*/
/**
@class
- @extends XM.Model
+ @extends XM.SimpleModel
*/
- // TODO - Switch to SimpleModel and fix bugs.
- XM.DatabaseServer = XM.Model.extend({
+ XM.DatabaseServer = XM.SimpleModel.extend({
/** @scope XM.DatabaseServer.prototype */
recordType: 'XM.DatabaseServer',
@@ -46,10 +45,9 @@ white:true*/
/**
@class
- @extends XM.Model
+ @extends XM.SimpleModel
*/
- // TODO - Switch to SimpleModel and fix bugs.
- XM.Extension = XM.Model.extend({
+ XM.Extension = XM.SimpleModel.extend({
/** @scope XM.Extension.prototype */
recordType: 'XM.Extension',
@@ -103,10 +101,9 @@ white:true*/
/**
@class
- @extends XM.Model
+ @extends XM.SimpleModel
*/
- // TODO - Switch to SimpleModel and fix bugs including removing findOrCreate.
- XM.Organization = XM.Model.extend({
+ XM.Organization = XM.SimpleModel.extend({
/** @scope XM.Organization.prototype */
recordType: 'XM.Organization',
@@ -122,10 +119,9 @@ white:true*/
/**
@class
- @extends XM.Model
+ @extends XM.SimpleModel
*/
- // TODO - Switch to SimpleModel and fix bugs. This almost works, just see some output to the datasource log.
- XM.OrganizationExtension = XM.Model.extend({
+ XM.OrganizationExtension = XM.SimpleModel.extend({
/** @scope XM.OrganizationExtension.prototype */
recordType: 'XM.OrganizationExtension',
View
51 node-datasource/lib/ext/pgworker.js
@@ -0,0 +1,51 @@
+/*jshint node:true, bitwise:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
+regexp:true, undef:true, strict:true, trailing:true, white:true */
+/*global issue:true */
+
+var pg = require('pg').native;
+var _ = require("underscore");
+
+pg.defaults.poolIdleTimeout = 10000;
+
+/**
+ * Connected.
+ */
+var connected = function (query, options, id, err, client, done, ranInit) {
+ "use strict";
+
+ if (err) {
+ done();
+ return process.send({err: err, id: id, options: options});
+ }
+
+ if (ranInit === true) {
+ client.hasRunInit = true;
+ }
+
+ if (!client.hasRunInit) {
+ client.query("set plv8.start_proc = \"xt.js_init\";", _.bind(
+ connected, this, query, options, id, err, client, done, true));
+ } else {
+ client.query(query, function (err, result) {
+ // Release the client from the pool.
+ done();
+
+ // Call the call back.
+ process.send({err: err, id: id, result: result});
+ });
+ }
+};
+
+process.on('message', function (message) {
+ "use strict";
+
+ var conString = message.conString,
+ id = message.id,
+ options = message.options,
+ poolSize = message.poolSize,
+ query = message.query;
+
+ pg.defaults.poolSize = poolSize;
+
+ pg.connect(conString, _.bind(connected, this, query, options, id));
+});
View
75 node-datasource/lib/ext/router.js
@@ -1,75 +0,0 @@
-/*jshint node:true, bitwise:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
-regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true, issue:true */
-
-(function () {
- "use strict";
-
- var _ = X._, _https = X.https;
-
- X.router = X.Object.create(/** @lends X.router */{
-
- hostname: X.options.datasource.bindAddress,
- port: 4430,//X.options.datasource.port,
-
- /**
- Change the password via the router
- */
- changePassword: function (target, payload, callback) {
- var req, options = {
- host: this.get("hostname"),
- port: this.get("port"),
- path: "/%@".f(target), // XXX how to get the ID into here?
- method: "POST"
- };
- req = _https.request(options, _.bind(this.didChangePassword, this, callback));
- req.on("error", _.bind(this.didError, this, callback));
- payload.changePassword = true;
- payload = X.json(payload);
- req.write(payload);
- req.end();
- },
- didChangePassword: function (callback, res) {
- var data = "";
- res.on("data", function (chunk) {
- data += chunk;
- });
- res.on("end", function () {
- var jsonData = X.json(data);
- if (jsonData.isError) {
- callback(jsonData, null);
- } else {
- callback(null, jsonData);
- }
- });
- },
- /**
- Lookup.
- */
- lookup: function (target, payload, callback) {
- var req, options = {
- host: this.get("hostname"),
- port: this.get("port"),
- path: "/%@".f(target),
- method: "POST"
- };
-
- req = _https.request(options, _.bind(this.didLookup, this, callback));
- req.on("error", _.bind(this.didError, this, callback));
- payload.lookup = true;
- payload = X.json(payload);
- req.write(payload);
- req.end();
- },
- didLookup: function (callback, res) {
- var data = "";
- res.on("data", function (chunk) { data += chunk; });
- res.on("end", function () { callback(null, X.json(data)); });
- },
- didError: function (callback, err) {
- X.warn("router error: ", err);
- callback(err);
- },
- className: "X.router"
- });
-}());
View
413 node-datasource/lib/ext/session.js
@@ -1,413 +0,0 @@
-/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
-regexp:true, undef:true, strict:true, trailing:true, white:true */
-/*global X:true, XM:true, issue:true, XT:true */
-
-(function () {
- "use strict";
-
- var _ = X._;
- //var _util = X.util;
-
- /**
- Session object for datasource.
-
- @class
- @extends X.Object
- */
- X.Session = X.Object.extend(/** @lends X.Session.prototype */{
-
- isReady: false,
- isLoaded: false,
-
- init: function () {
- var id = this.get("id"), sid = this.get("sid"),
- selected = this.get("selected"), logout = this.get("logout");
-
- if (logout) {
- this.load(_.bind(this.didLoadForLogout, this));