Got print checkbox working
[xtuple] / enyo-client / application / source / views / workspace.js
1 /*jshint bitwise:false, indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
2 newcap:true, noarg:true, regexp:true, undef:true, trailing:true, white:true,
3 strict: false*/
4 /*global XV:true, XM:true, _:true, enyo:true, XT:true, onyx:true, window:true */
5
6 (function () {
7
8   var hash;
9
10   /**
11     Used to notify change of account to contact widget if both exist on
12     the same workspace.
13   */
14   XV.accountNotifyContactMixin = {
15     accountChanged: function () {
16       var account = this.$.accountWidget.getValue();
17       if (account) {
18         this.$.contactWidget.addParameter({
19           attribute: ["account", "accountParent"],
20           value: account.id
21         }, true);
22       } else {
23         this.$.contactWidget.removeParameter("account");
24       }
25     },
26     attributesChanged: function (inSender, inEvent) {
27       this.inherited(arguments);
28       this.accountChanged();
29     },
30     controlValueChanged: function (inSender, inEvent) {
31       this.inherited(arguments);
32       if (inEvent.originator.name === 'accountWidget') {
33         this.accountChanged();
34       }
35     }
36   };
37
38   /**
39     Handles Address change with prompts.
40   */
41   XV.WorkspaceAddressMixin = {
42     accountChanged: function () {
43       var account = this.getAccount();
44       this.$.addressWidget.setAccount(account);
45     },
46     attributesChanged: function (inSender, inEvent) {
47       this.inherited(arguments);
48       this.accountChanged();
49     },
50     controlValueChanged: function (inSender, inEvent) {
51       this.inherited(arguments);
52       if (inEvent.originator.name === 'accountWidget' ||
53           inEvent.originator.name === 'customerWidget') {
54         this.accountChanged();
55       }
56     },
57     getAccount: function () {
58       var model = this.getValue();
59       return model ? (model.get('account') || model.get('customer')) : undefined;
60     }
61   };
62
63   /**
64     Abstract workspace to be used for objects that are attached to models subclassed
65       from `AccountDocument`.
66     Must be subclassed.
67   */
68   enyo.kind({
69     name: "XV.AccountDocumentWorkspace",
70     kind: "XV.Workspace",
71     handlers: {
72       onError: "errorNotify"
73     },
74     published: {
75       // The natural key is the number, not the UUID
76       existingNumber: ""
77     },
78     accountConvert: function (inEvent) {
79       this.value.convertFromAccount(this.existingNumber);
80       this._popupDone = true;
81       this.$.findExistingAccountPopup.hide();
82     },
83     errorNotify: function (inSender, inEvent) {
84       // Handle existing
85       if (inEvent.error.code === 'xt1008') {
86         this.existingNumber = inEvent.error.params.response.id;
87         this._popupDone = false;
88         this.$.findExistingAccountPopup.show();
89         return true;
90       }
91     },
92     accountCancel: function () {
93       this._popupDone = true;
94       this.$.findExistingAccountPopup.hide();
95     },
96     popupHidden: function () {
97       if (!this._popupDone) {
98         this.$.findExistingAccountPopup.show();
99         return true;
100       }
101     }
102   });
103
104   // ..........................................................
105   // EMAIL PROFILE
106   //
107
108   /**
109     An abstract workspace for email profiles.
110   */
111   enyo.kind({
112     name: "XV.EmailProfileWorkspace",
113     kind: "XV.Workspace",
114     headerAttrs: ["name", "-", "description"],
115     components: [
116       {kind: "Panels", arrangerKind: "CarouselArranger",
117         fit: true, components: [
118         {kind: "XV.Groupbox", name: "mainPanel", components: [
119           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
120           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
121             classes: "in-panel", components: [
122             {kind: "XV.InputWidget", attr: "name"},
123             {kind: "XV.InputWidget", attr: "description"},
124             {kind: "onyx.GroupboxHeader", content: "_header".loc()},
125             {kind: "XV.InputWidget", attr: "from"},
126             {kind: "XV.InputWidget", attr: "replyTo"},
127             {kind: "XV.InputWidget", attr: "to"},
128             {kind: "XV.InputWidget", attr: "cc"},
129             {kind: "XV.InputWidget", attr: "bcc"},
130             {kind: "XV.InputWidget", attr: "subject"},
131             {kind: "onyx.GroupboxHeader", content: "_body".loc()},
132             {kind: "XV.TextArea", attr: "body", classes: "max-height"}
133           ]}
134         ]}
135       ]}
136     ]
137   });
138
139   // ..........................................................
140   // BASE CLASS
141   //
142
143   enyo.kind({
144     name: "XV.OrderedReferenceWorkspace",
145     kind: "XV.Workspace",
146     components: [
147       {kind: "Panels", arrangerKind: "CarouselArranger",
148         fit: true, components: [
149         {kind: "XV.Groupbox", name: "mainPanel", components: [
150           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
151           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
152             classes: "in-panel", components: [
153             {kind: "XV.InputWidget", attr: "name"},
154             {kind: "XV.InputWidget", attr: "description"},
155             // these order fields are integers, so setting a maxlength
156             // to prevent exceeding integer's max value
157             {kind: "XV.NumberWidget", attr: "order", maxlength: 9, formatting: false}
158           ]}
159         ]}
160       ]}
161     ]
162   });
163
164   // ..........................................................
165   // ACCOUNT
166   //
167
168   enyo.kind({
169     name: "XV.AccountWorkspace",
170     kind: "XV.Workspace",
171     title: "_account".loc(),
172     headerAttrs: ["number", "-", "name"],
173     model: "XM.Account",
174     handlers: {
175       onSavePrompt: "savePrompt"
176     },
177     components: [
178       {kind: "Panels", arrangerKind: "CarouselArranger",
179         fit: true, components: [
180         {kind: "XV.Groupbox", name: "mainPanel", components: [
181           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
182           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
183             classes: "in-panel", components: [
184             {kind: "XV.InputWidget", attr: "number"},
185             {kind: "XV.CheckboxWidget", attr: "isActive"},
186             {kind: "XV.InputWidget", attr: "name"},
187             {kind: "XV.AccountTypePicker", attr: "accountType"},
188             {kind: "XV.AccountWidget", attr: "parent", label: "_parent".loc()},
189             {kind: "XV.UserAccountWidget", attr: "owner"},
190             {kind: "onyx.GroupboxHeader", content: "_primaryContact".loc()},
191             {kind: "XV.ContactWidget", attr: "primaryContact",
192               showAddress: true, label: "_name".loc()},
193             {kind: "onyx.GroupboxHeader", content: "_secondaryContact".loc()},
194             {kind: "XV.ContactWidget", attr: "secondaryContact",
195               showAddress: true, label: "_name".loc()},
196             {kind: "XV.AccountCharacteristicsWidget", attr: "characteristics"},
197             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
198             {kind: "XV.TextArea", attr: "notes", fit: true}
199           ]}
200         ]},
201         {kind: "XV.AccountCommentBox", attr: "comments"},
202         {kind: "XV.Groupbox", name: "rolesPanel", title: "_roles".loc(),
203           components: [
204           {kind: "onyx.GroupboxHeader", content: "_roles".loc()},
205           {kind: "XV.ScrollableGroupbox", name: "rolesGroup", fit: true,
206             classes: "in-panel", components: []
207           }
208         ]},
209         {kind: "XV.AccountDocumentsBox", attr: "documents"},
210         {kind: "XV.AccountContactsBox", attr: "contactRelations"}
211       ]},
212       {kind: "onyx.Popup", name: "savePromptPopup", centered: true,
213         modal: true, floating: true, scrim: true,
214         onHide: "popupHidden", components: [
215         {content: "_mustSave".loc() },
216         {content: "_saveYourWork?".loc() },
217         {tag: "br"},
218         {kind: "onyx.Button", content: "_cancel".loc(), ontap: "savePromptCancel",
219           classes: "xv-popup-button"},
220         {kind: "onyx.Button", content: "_save".loc(), ontap: "savePromptSave",
221           classes: "onyx-blue xv-popup-button"}
222       ]}
223     ],
224     create: function () {
225       this.inherited(arguments);
226       var K = XM.Account.prototype,
227         roles = K.roleAttributes.sort(),
228         that = this;
229
230       // Loop and add a role checkbox for each role attribute found on the model
231       _.each(roles, function (role) {
232         that.createComponent({
233           kind: XV.AccountRoleCheckboxWidget,
234           name: role + "Control",
235           label: ("_" + role).loc(),
236           attr: role,
237           container: that.$.rolesGroup,
238           owner: that
239         });
240       });
241
242     },
243     savePrompt: function (inSender, inEvent) {
244       this._popupDone = false;
245       this._inEvent = inEvent;
246       this.$.savePromptPopup.show();
247     },
248     savePromptCancel: function () {
249       this._popupDone = true;
250       this._inEvent.callback(false);
251       this.$.savePromptPopup.hide();
252     },
253     savePromptSave: function () {
254       var that = this,
255         options = {};
256       options.success = function () {
257         that._inEvent.callback(true);
258       };
259       this._popupDone = true;
260       this.$.savePromptPopup.hide();
261       this.save(options);
262     }
263   });
264
265   XV.registerModelWorkspace("XM.AccountRelation", "XV.AccountWorkspace");
266   XV.registerModelWorkspace("XM.AccountListItem", "XV.AccountWorkspace");
267
268   // ..........................................................
269   // BANK ACCOUNT
270   //
271
272   enyo.kind({
273     name: "XV.BankAccountWorkspace",
274     kind: "XV.Workspace",
275     title: "_bankAccount".loc(),
276     model: "XM.BankAccount",
277     components: [
278       {kind: "Panels", arrangerKind: "CarouselArranger",
279         fit: true, components: [
280         {kind: "XV.Groupbox", name: "mainPanel", components: [
281           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
282           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
283             classes: "in-panel", fit: true, components: [
284             {kind: "XV.InputWidget", attr: "name"},
285             {kind: "XV.InputWidget", attr: "description"},
286             {kind: "XV.InputWidget", attr: "bankName"},
287             {kind: "XV.InputWidget", attr: "accountNumber"},
288             {kind: "XV.BankAccountTypePicker", attr: "bankAccountType"},
289             {kind: "XV.CurrencyPicker", attr: "currency"},
290             {kind: "XV.CheckboxWidget", attr: "isUsedByBilling"},
291             {kind: "XV.CheckboxWidget", attr: "isUsedByPayments"},
292             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
293             {kind: "XV.TextArea", attr: "notes"}
294           ]}
295         ]}
296       ]}
297     ]
298   });
299
300   XV.registerModelWorkspace("XM.BankAccountRelation", "XV.BankAccountWorkspace");
301
302   // ..........................................................
303   // CHARACTERISTIC
304   //
305
306   enyo.kind({
307     name: "XV.CharacteristicWorkspace",
308     kind: "XV.Workspace",
309     title: "_characteristic".loc(),
310     model: "XM.Characteristic",
311     components: [
312       {kind: "Panels", arrangerKind: "CarouselArranger",
313         fit: true, components: [
314         {kind: "XV.Groupbox", name: "mainPanel", components: [
315           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
316           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
317             classes: "in-panel", components: [
318             {kind: "XV.InputWidget", attr: "name"},
319             {kind: "XV.CharacteristicTypePicker", name: "typePicker", attr: "characteristicType"},
320             {kind: "XV.CheckboxWidget", attr: "isSearchable"},
321             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
322             {kind: "XV.TextArea", attr: "notes", fit: true, name: "notesHeader"},
323             {name: "advancedPanel", showing: false, components: [
324               {kind: "onyx.GroupboxHeader", content: "_advanced".loc()},
325               {kind: "XV.InputWidget", attr: "mask"},
326               {kind: "XV.InputWidget", attr: "validator"}
327             ]}
328           ]}
329         ]},
330         {kind: "XV.Groupbox", name: "rolesPanel", title: "_roles".loc(),
331           components: [
332           {kind: "onyx.GroupboxHeader", content: "_roles".loc()},
333           {kind: "XV.ScrollableGroupbox", name: "rolesGroup", fit: true,
334             classes: "in-panel", components: [
335             {kind: "XV.ToggleButtonWidget", attr: "isAccounts", label: "_accounts".loc()},
336             {kind: "XV.ToggleButtonWidget", attr: "isAddresses", label: "_addresses".loc()},
337             {kind: "XV.ToggleButtonWidget", attr: "isContacts", label: "_contacts".loc()},
338             {kind: "XV.ToggleButtonWidget", attr: "isCustomers", label: "_customers".loc()},
339             {kind: "XV.ToggleButtonWidget", attr: "isEmployees", label: "_employees".loc()},
340             {kind: "XV.ToggleButtonWidget", attr: "isIncidents", label: "_incidents".loc()},
341             {kind: "XV.ToggleButtonWidget", attr: "isInvoices", label: "_invoices".loc()},
342             {kind: "XV.ToggleButtonWidget", attr: "isItems", label: "_items".loc()},
343             {kind: "XV.ToggleButtonWidget", attr: "isOpportunities", label: "_opportunities".loc()},
344             {kind: "XV.ToggleButtonWidget", attr: "isSalesOrders", label: "_salesOrders".loc()},
345           ]}
346         ]},
347         {kind: "XV.CharacteristicOptionBox", name: "optionsPanel",
348           attr: "options", showing: false}
349       ]}
350     ],
351     /**
352       After the controls are updated by the model, determine visibility of panels.
353      */
354     attributesChanged: function (model, options) {
355       this.inherited(arguments);
356       if (this.getValue().getStatus() === XM.Model.READY_CLEAN ||
357         this.getValue().getStatus() === XM.Model.READY_NEW) {
358         this.typeValueChanged(model);
359       }
360     },
361
362     /**
363       Function to determine visibility of "advanced" and "options" panels based
364         on the characteristicType
365      */
366     typeValueChanged: function (model) {
367       var type = model ? model.get('characteristicType') : null;
368       var isText = type === XM.Characteristic.TEXT;
369       var isList = type === XM.Characteristic.LIST;
370       this.$.advancedPanel.setShowing(isText);
371       this.$.optionsPanel.setShowing(isList);
372       if (isList) {
373         this.$.optionsPanel.render();
374       } else if (isText) {
375         this.$.advancedPanel.render();
376       }
377       // signal to workspace container that the menu needs to re-render
378       this.doMenuChange();
379     }
380   });
381
382   XV.registerModelWorkspace("XM.Characteristic", "XV.CharacteristicWorkspace");
383
384   // ..........................................................
385   // CLASS CODE
386   //
387
388   enyo.kind({
389     name: "XV.ClassCodeWorkspace",
390     kind: "XV.Workspace",
391     title: "_classCode".loc(),
392     model: "XM.ClassCode",
393     components: [
394       {kind: "Panels", arrangerKind: "CarouselArranger",
395         fit: true, components: [
396         {kind: "XV.Groupbox", name: "mainPanel", components: [
397           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
398           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
399             classes: "in-panel", components: [
400             {kind: "XV.InputWidget", attr: "code"},
401             {kind: "XV.InputWidget", attr: "description"}
402           ]}
403         ]}
404       ]}
405     ]
406   });
407
408   XV.registerModelWorkspace("XM.ClassCode", "XV.ClassCodeWorkspace");
409
410   // ..........................................................
411   // CONFIGURE
412   //
413
414   enyo.kind({
415     name: "XV.DatabaseInformationWorkspace",
416     kind: "XV.Workspace",
417     title: "_database".loc() + " " + "_information".loc(),
418     model: "XM.DatabaseInformation",
419     components: [
420       {kind: "Panels", arrangerKind: "CarouselArranger",
421         fit: true, components: [
422         {kind: "XV.Groupbox", name: "mainPanel", components: [
423           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
424           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
425             classes: "in-panel", components: [
426             {kind: "XV.InputWidget", attr: "DatabaseName",
427               label: "_name".loc()},
428             {kind: "XV.InputWidget", attr: "ServerVersion",
429                 label: "_version".loc()},
430             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
431             {kind: "XV.TextArea", attr: "DatabaseComments"}
432           ]}
433         ]}
434       ]}
435     ]
436   });
437
438   enyo.kind({
439     name: "XV.SystemConfigurationWorkspace",
440     kind: "XV.Workspace",
441     title: "_systemConfiguration".loc(),
442     model: "XM.System",
443     components: [
444       {kind: "Panels", arrangerKind: "CarouselArranger",
445         fit: true, components: [
446         {kind: "XV.Groupbox", name: "mainPanel", title: "_creditCard".loc(),
447           components: [
448           {kind: "onyx.GroupboxHeader", content: "_default".loc()},
449           {kind: "XV.PriorityPicker", attr: "DefaultPriority",
450             label: "_priority".loc()},
451           {kind: "onyx.GroupboxHeader", content: "_creditCard".loc()},
452           {kind: "XV.ScrollableGroupbox", name: "mainGroup", classes: "in-panel", components: [
453             {kind: "XV.CreditCardGatewayCombobox", attr: "CCCompany",
454                 label: "_gateway".loc()},
455             {kind: "XV.InputWidget", attr: "CCLogin",
456               label: "_login".loc()},
457             {kind: "XV.InputWidget", attr: "CCPassword",
458                 label: "_password".loc()},
459             {kind: "XV.ToggleButtonWidget", attr: "CCTest",
460                 label: "_testMode".loc()},
461             {kind: "XV.ToggleButtonWidget", attr: "CCRequireCCV",
462                 label: "_requireCCV".loc()}
463           ]}
464         ]}
465       ]}
466     ]
467   });
468
469   enyo.kind({
470     name: "XV.UserPreferenceWorkspace",
471     kind: "XV.Workspace",
472     title: "_userPreferences".loc(),
473     model: "XM.UserPreference",
474     published: {
475       singletonModel: "XT.session.preferences"
476     },
477     components: [
478       {kind: "Panels", arrangerKind: "CarouselArranger",
479         fit: true, components: [
480         {kind: "XV.Groupbox", name: "mainPanel", components: [
481           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
482           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
483             classes: "in-panel", components: [
484           ]}
485         ]}
486       ]}
487     ]
488   });
489
490   // ..........................................................
491   // CONTACT
492   //
493
494   hash = {
495     name: "XV.ContactWorkspace",
496     kind: "XV.Workspace",
497     title: "_contact".loc(),
498     model: "XM.Contact",
499     headerAttrs: ["firstName", "lastName"],
500     handlers: {
501       onError: "errorNotify"
502     },
503     components: [
504       {kind: "Panels", arrangerKind: "CarouselArranger",
505         fit: true, components: [
506         {kind: "XV.Groupbox", name: "mainPanel", components: [
507           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
508           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
509             classes: "in-panel", components: [
510             {kind: "XV.InputWidget", attr: "number"},
511             {kind: "XV.CheckboxWidget", attr: "isActive"},
512             {kind: "onyx.GroupboxHeader", content: "_name".loc()},
513             {kind: "XV.HonorificCombobox", attr: "honorific"},
514             {kind: "XV.InputWidget", attr: "firstName"},
515             {kind: "XV.InputWidget", attr: "middleName"},
516             {kind: "XV.InputWidget", attr: "lastName"},
517             {kind: "XV.InputWidget", attr: "suffix"},
518             {kind: "onyx.GroupboxHeader", content: "_relationships".loc()},
519             {kind: "XV.UserAccountWidget", attr: "owner"},
520             {kind: "XV.AccountWidget", attr: "account"},
521             {kind: "onyx.GroupboxHeader", content: "_address".loc()},
522             {kind: "XV.AddressWidget", attr: "address"},
523             {kind: "onyx.GroupboxHeader", content: "_information".loc()},
524             {kind: "XV.InputWidget", attr: "jobTitle"},
525             {kind: "XV.ComboboxWidget", attr: "primaryEmail",
526               keyAttribute: "email"},
527             {kind: "XV.InputWidget", attr: "phone"},
528             {kind: "XV.InputWidget", attr: "alternate"},
529             {kind: "XV.InputWidget", attr: "fax"},
530             {kind: "XV.InputWidget", attr: "webAddress"},
531             {kind: "XV.ContactCharacteristicsWidget", attr: "characteristics"},
532             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
533             {kind: "XV.TextArea", attr: "notes"}
534           ]}
535         ]},
536         {kind: "XV.ContactCommentBox", attr: "comments"},
537         {kind: "XV.ContactDocumentsBox", attr: "documents"},
538         {kind: "XV.ContactEmailBox", attr: "email"}
539       ]}
540     ]
541   };
542   hash = enyo.mixin(hash, XV.WorkspaceAddressMixin);
543   enyo.kind(hash);
544
545   XV.registerModelWorkspace("XM.ContactRelation", "XV.ContactWorkspace");
546   XV.registerModelWorkspace("XM.ContactListItem", "XV.ContactWorkspace");
547
548   // ..........................................................
549   // COST CATEGORY
550   //
551
552   enyo.kind({
553     name: "XV.CostCategoryWorkspace",
554     kind: "XV.Workspace",
555     title: "_costCategory".loc(),
556     model: "XM.CostCategory",
557     components: [
558       {kind: "Panels", arrangerKind: "CarouselArranger",
559         fit: true, components: [
560         {kind: "XV.Groupbox", name: "mainPanel", components: [
561           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
562           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
563             classes: "in-panel", components: [
564             {kind: "XV.InputWidget", attr: "code"},
565             {kind: "XV.InputWidget", attr: "description"}
566           ]}
567         ]}
568       ]}
569     ]
570   });
571
572   XV.registerModelWorkspace("XM.CostCategory", "XV.CostCategoryWorkspace");
573
574
575   // ..........................................................
576   // COUNTRY
577   //
578
579   enyo.kind({
580     name: "XV.CountryWorkspace",
581     kind: "XV.Workspace",
582     title: "_country".loc(),
583     model: "XM.Country",
584     components: [
585       {kind: "Panels", arrangerKind: "CarouselArranger",
586         fit: true, components: [
587         {kind: "XV.Groupbox", name: "mainPanel", components: [
588           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
589           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
590             classes: "in-panel", components: [
591             {kind: "XV.InputWidget", attr: "abbreviation"},
592             {kind: "XV.InputWidget", attr: "name"},
593             {kind: "XV.InputWidget", attr: "currencyName"},
594             {kind: "XV.InputWidget", attr: "currencySymbol"},
595             {kind: "XV.InputWidget", attr: "currencyAbbreviation"},
596             {kind: "XV.InputWidget", attr: "currencyNumber"}
597           ]}
598         ]}
599       ]}
600     ]
601   });
602
603   XV.registerModelWorkspace("XM.Country", "XV.CountryWorkspace");
604
605   // ..........................................................
606   // CURRENCY
607   //
608
609   enyo.kind({
610     name: "XV.CurrencyWorkspace",
611     kind: "XV.Workspace",
612     title: "_currency".loc(),
613     model: "XM.Currency",
614     components: [
615       {kind: "Panels", arrangerKind: "CarouselArranger",
616         fit: true, components: [
617         {kind: "XV.Groupbox", name: "mainPanel", components: [
618           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
619           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
620             classes: "in-panel", components: [
621             {kind: "XV.InputWidget", attr: "abbreviation"},
622             {kind: "XV.InputWidget", attr: "name"},
623             {kind: "XV.InputWidget", attr: "symbol"}
624           ]}
625         ]}
626       ]}
627     ]
628   });
629
630   XV.registerModelWorkspace("XM.Currency", "XV.CurrencyWorkspace");
631
632   // ..........................................................
633   // CUSTOMER
634   //
635
636   enyo.kind({
637     name: "XV.CustomerWorkspace",
638     kind: "XV.Workspace",
639     title: "_customer".loc(),
640     model: "XM.Customer",
641     headerAttrs: ["number", "-", "name"],
642     handlers: {
643       onError: "errorNotify"
644     },
645     published: {
646       // The natural key is Number, not UUID
647       existingNumber: ""
648     },
649     components: [
650       {kind: "Panels", arrangerKind: "CarouselArranger",
651         fit: true, components: [
652         {kind: "XV.Groupbox", name: "mainPanel", components: [
653           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
654           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
655             classes: "in-panel", components: [
656             {kind: "XV.InputWidget", attr: "number"},
657             {kind: "XV.InputWidget", attr: "name"},
658             {kind: "XV.CustomerTypePicker", attr: "customerType"},
659             {kind: "XV.CheckboxWidget", attr: "isActive"},
660             {kind: "onyx.GroupboxHeader", content: "_billingContact".loc()},
661             {kind: "XV.ContactWidget", attr: "billingContact",
662               showAddress: true, label: "_name".loc()},
663             {kind: "onyx.GroupboxHeader", content: "_correspondenceContact".loc()},
664             {kind: "XV.ContactWidget", attr: "correspondenceContact",
665               showAddress: true, label: "_name".loc()},
666             {kind: "XV.CustomerCharacteristicsWidget", attr: "characteristics"},
667             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
668             {kind: "XV.TextArea", attr: "notes"}
669           ]}
670         ]},
671         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(), components: [
672           {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
673           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
674             classes: "in-panel", components: [
675             {kind: "XV.SalesRepPicker", attr: "salesRep"},
676             {kind: "XV.PercentWidget", attr: "commission"},
677             {kind: "XV.ShipViaCombobox", attr: "shipVia"},
678             {kind: "XV.ShippingChargePicker", attr: "shipCharge"},
679             {kind: "XV.CustomerEmailProfilePicker", attr: "emailProfile"},
680             {kind: "XV.CheckboxWidget", attr: "backorder"},
681             {kind: "XV.CheckboxWidget", attr: "partialShip"},
682             {kind: "XV.CheckboxWidget", attr: "isFreeFormShipto", label: "_freeFormShip".loc()},
683             {kind: "XV.CheckboxWidget", attr: "isFreeFormBillto", label: "_freeFormBill".loc()},
684             {kind: "onyx.GroupboxHeader", content: "_terms".loc()},
685             {kind: "XV.BillingTermsPicker", attr: "terms"},
686             {kind: "XV.PercentWidget", attr: "discount"},
687             {kind: "XV.CreditStatusPicker", attr: "creditStatus"},
688             {kind: "XV.CheckboxWidget", attr: "usesPurchaseOrders"},
689             {kind: "XV.CheckboxWidget", attr: "blanketPurchaseOrders"},
690             {kind: "XV.BalanceMethodPicker", attr: "balanceMethod"},
691             {kind: "XV.NumberWidget", attr: "creditLimit"},
692             {kind: "XV.InputWidget", attr: "creditRating"},
693             {kind: "XV.NumberWidget", attr: "graceDays"},
694             {kind: "onyx.GroupboxHeader", content: "_tax".loc()},
695             {kind: "XV.TaxZonePicker", attr: "taxZone", label: "_defaultTaxZone".loc()}
696           ]}
697         ]},
698         {kind: "XV.CustomerShipToBox", attr: "shiptos"},
699         {kind: "XV.CustomerCommentBox", attr: "comments"},
700         {kind: "XV.CreditCardsBox", attr: "creditCards"},
701         {kind: "XV.TaxRegistrationBox", attr: "taxRegistration"},
702         {kind: "XV.CustomerDocumentsBox", attr: "documents"},
703         {kind: "XV.CustomerQuoteListRelationsBox", attr: "quoteRelations"},
704         {kind: "XV.CustomerSalesOrderListRelationsBox", attr: "salesOrderRelations"},
705       ]},
706       // TODO: move this to notify system
707       {kind: "onyx.Popup", name: "findExistingCustomerPopup", centered: true,
708         modal: true, floating: true, scrim: true, onShow: "popupShown",
709         onHide: "popupHidden", components: [
710         {name: "exists"},
711         {name: "whatToDo"},
712         {tag: "br"},
713         {kind: "onyx.Button", name: "ok", content: "_ok".loc(), ontap: "customerConvert",
714           classes: "onyx-blue xv-popup-button", type: ""},
715         {kind: "onyx.Button", name: "cancel", content: "_cancel".loc(), ontap: "customerCancel",
716           classes: "xv-popup-button", type: ""}
717       ]}
718     ],
719     customerConvert: function (inEvent) {
720       this._popupDone = true;
721       this.$.findExistingCustomerPopup.hide();
722       if (inEvent.type === "prospect") {
723         this.value.convertFromProspect(this.existingNumber);
724       } else if (inEvent.type === "account") {
725         this.value.convertFromAccount(this.existingNumber);
726       }
727     },
728     errorNotify: function (inSender, inEvent) {
729       // Handle customer existing as prospect
730       if (inEvent.error.code === 'xt1008') {
731         var type = inEvent.error.params.response.type;
732         this.existingNumber = inEvent.error.params.response.id;
733         if (type === 'P') { // Prospect
734           this._popupDone = false;
735           this.$.exists.setContent("_prospectExists".loc());
736           this.$.whatToDo.setContent("_convertProspect".loc());
737           this.$.ok.type = "prospect";
738           this.$.findExistingCustomerPopup.show();
739           return true;
740         } else if (type === 'A') { // Existing Account
741           this._popupDone = false;
742           this.$.exists.setContent("_accountExists".loc());
743           this.$.whatToDo.setContent("_convertAccount".loc());
744           this.$.ok.type = "account";
745           this.$.findExistingCustomerPopup.show();
746           return true;
747         }
748       }
749     },
750     customerCancel: function () {
751       this._popupDone = true;
752       this.$.findExistingCustomerPopup.hide();
753       return true;
754     },
755     popupHidden: function () {
756       if (!this._popupDone) {
757         this.$.findExistingCustomerPopup.show();
758         return true;
759       }
760     }
761   });
762
763   XV.registerModelWorkspace("XM.CustomerRelation", "XV.CustomerWorkspace");
764   XV.registerModelWorkspace("XM.CustomerListItem", "XV.CustomerWorkspace");
765   XV.registerModelWorkspace("XM.CustomerProspectListItem", "XV.CustomerWorkspace");
766
767   // ..........................................................
768   // CUSTOMER EMAIL PROFILE
769   //
770
771   enyo.kind({
772     name: "XV.CustomerEmailProfileWorkspace",
773     kind: "XV.EmailProfileWorkspace",
774     title: "_customerEmailProfile".loc(),
775     model: "XM.CustomerEmailProfile",
776   });
777
778   XV.registerModelWorkspace("XM.CustomerEmailProfile", "XV.CustomerEmailProfileWorkspace");
779
780   // ..........................................................
781   // CUSTOMER GROUP
782   //
783
784   enyo.kind({
785     name: "XV.CustomerGroupWorkspace",
786     kind: "XV.Workspace",
787     title: "_customerGroup".loc(),
788     model: "XM.CustomerGroup",
789     components: [
790       {kind: "Panels", arrangerKind: "CarouselArranger",
791         fit: true, components: [
792         {kind: "XV.Groupbox", name: "mainPanel", components: [
793           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
794           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
795             classes: "in-panel", components: [
796             {kind: "XV.InputWidget", attr: "name"},
797             {kind: "XV.InputWidget", attr: "description"}
798           ]}
799         ]},
800         {kind: "XV.CustomerGroupCustomerBox", attr: "customers"}
801       ]}
802     ]
803   });
804
805   XV.registerModelWorkspace("XM.CustomerGroup", "XV.CustomerGroupWorkspace");
806
807   // ..........................................................
808   // CUSTOMER TYPE
809   //
810
811   enyo.kind({
812     name: "XV.CustomerTypeWorkspace",
813     kind: "XV.Workspace",
814     title: "_customerType".loc(),
815     model: "XM.CustomerType",
816     components: [
817       {kind: "Panels", arrangerKind: "CarouselArranger",
818         fit: true, components: [
819         {kind: "XV.Groupbox", name: "mainPanel", components: [
820           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
821           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
822             classes: "in-panel", components: [
823             {kind: "XV.InputWidget", attr: "code"},
824             {kind: "XV.InputWidget", attr: "description"}
825           ]}
826         ]}
827       ]}
828     ]
829   });
830
831   XV.registerModelWorkspace("XM.CustomerType", "XV.CustomerTypeWorkspace");
832
833   // ..........................................................
834   // CLASS CODE
835   //
836
837   enyo.kind({
838     name: "XV.ExpenseCategoryWorkspace",
839     kind: "XV.Workspace",
840     title: "_expenseCategory".loc(),
841     model: "XM.ExpenseCategory",
842     components: [
843       {kind: "Panels", arrangerKind: "CarouselArranger",
844         fit: true, components: [
845         {kind: "XV.Groupbox", name: "mainPanel", components: [
846           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
847           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
848             classes: "in-panel", components: [
849             {kind: "XV.InputWidget", attr: "code"},
850             {kind: "XV.InputWidget", attr: "description"}
851           ]}
852         ]}
853       ]}
854     ]
855   });
856
857   XV.registerModelWorkspace("XM.ExpenseCategory", "XV.ExpenseCategoryWorkspace");
858
859   // ..........................................................
860   // DEPARTMENT
861   //
862
863   enyo.kind({
864     name: "XV.DepartmentWorkspace",
865     kind: "XV.Workspace",
866     title: "_department".loc(),
867     model: "XM.Department",
868     components: [
869       {kind: "Panels", arrangerKind: "CarouselArranger",
870         fit: true, components: [
871         {kind: "XV.Groupbox", name: "mainPanel", components: [
872           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
873           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
874             classes: "in-panel", components: [
875             {kind: "XV.InputWidget", attr: "number"},
876             {kind: "XV.InputWidget", attr: "name"}
877           ]}
878         ]}
879       ]}
880     ]
881   });
882
883   XV.registerModelWorkspace("XM.Department", "XV.DepartmentWorkspace");
884
885   // ..........................................................
886   // EMPLOYEE
887   //
888
889   enyo.kind({
890     name: "XV.EmployeeWorkspace",
891     kind: "XV.AccountDocumentWorkspace",
892     title: "_employee".loc(),
893     model: "XM.Employee",
894     headerAttrs: ["number", "-", "name"],
895     components: [
896       {kind: "Panels", arrangerKind: "CarouselArranger",
897         fit: true, components: [
898         {kind: "XV.Groupbox", name: "mainPanel", components: [
899           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
900           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
901             classes: "in-panel", components: [
902             {kind: "XV.InputWidget", attr: "code"},
903             {kind: "XV.InputWidget", attr: "number"},
904             {kind: "XV.InputWidget", attr: "name"},
905             {kind: "XV.CheckboxWidget", attr: "isActive"},
906             {kind: "onyx.GroupboxHeader", content: "_contact".loc()},
907             {kind: "XV.ContactWidget", attr: "contact",
908               showAddress: true, label: "_name".loc()},
909             {kind: "XV.EmployeeCharacteristicsWidget", attr: "characteristics"},
910             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
911             {kind: "XV.TextArea", attr: "notes"}
912           ]}
913         ]},
914         {kind: "XV.Groupbox", name: "detailPanel", title: "_detail".loc(),
915           components: [
916           {kind: "onyx.GroupboxHeader", content: "_detail".loc()},
917           {kind: "XV.ScrollableGroupbox", name: "detailGroup", fit: true,
918             classes: "in-panel", components: [
919             {kind: "XV.DateWidget", attr: "startDate"},
920             {kind: "XV.SitePicker", attr: "site"},
921             {kind: "XV.DepartmentWidget", attr: "department"},
922             {kind: "XV.EmployeeWidget", attr: "manager"},
923             {kind: "XV.ShiftWidget", attr: "shift"},
924             {kind: "onyx.GroupboxHeader", content: "_financials".loc()},
925             {kind: "XV.WageTypePicker", attr: "wageType"},
926             {kind: "XV.MoneyWidget",
927               attr: {localValue: "wage", currency: "wageCurrency"},
928               currencyDisabled: true},
929             {kind: "XV.WagePeriodPicker", attr: "wagePeriod", label: "_period".loc()},
930             {kind: "XV.MoneyWidget",
931               attr: {localValue: "billingRate", currency: "billingCurrency"},
932               currencyDisabled: true},
933             {kind: "XV.WagePeriodPicker", attr: "billingPeriod", label: "_period".loc()}
934           ]}
935         ]},
936         {kind: "XV.EmployeeCommentBox", attr: "comments"},
937         {kind: "XV.EmployeeGroupGroupBox", attr: "groups"}
938       ]},
939       {kind: "onyx.Popup", name: "findExistingAccountPopup", centered: true,
940         modal: true, floating: true, scrim: true, onShow: "popupShown",
941         onHide: "popupHidden", components: [
942         {content: "_accountExists".loc()},
943         {name: "whatToDo", content: "_convertAccountEmployee".loc()},
944         {tag: "br"},
945         {kind: "onyx.Button", name: "convert", content: "_ok".loc(), ontap: "accountConvert",
946           classes: "onyx-blue xv-popup-button"},
947         {kind: "onyx.Button", name: "cancel", content: "_cancel".loc(), ontap: "accountCancel",
948           classes: "xv-popup-button"}
949       ]}
950     ]
951   });
952
953   XV.registerModelWorkspace("XM.EmployeeRelation", "XV.EmployeeWorkspace");
954   XV.registerModelWorkspace("XM.EmployeeListItem", "XV.EmployeeWorkspace");
955
956   // ..........................................................
957   // EMPLOYEE GROUP
958   //
959
960   enyo.kind({
961     name: "XV.EmployeeGroupWorkspace",
962     kind: "XV.Workspace",
963     title: "_employeeGroup".loc(),
964     model: "XM.EmployeeGroup",
965     components: [
966       {kind: "Panels", arrangerKind: "CarouselArranger",
967         fit: true, components: [
968         {kind: "XV.Groupbox", name: "mainPanel", components: [
969           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
970           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
971             classes: "in-panel", components: [
972             {kind: "XV.InputWidget", attr: "name"},
973             {kind: "XV.InputWidget", attr: "description"}
974           ]}
975         ]},
976         {kind: "XV.EmployeeGroupEmployeeBox", attr: "employees"}
977       ]}
978     ]
979   });
980
981   XV.registerModelWorkspace("XM.EmployeeGroup", "XV.EmployeeGroupWorkspace");
982
983   // ..........................................................
984   // FILE
985   //
986
987   enyo.kind({
988     name: "XV.FileWorkspace",
989     kind: "XV.Workspace",
990     title: "_file".loc(),
991     model: "XM.File",
992     components: [
993       {kind: "Panels", arrangerKind: "CarouselArranger",
994         fit: true, components: [
995         {kind: "XV.Groupbox", name: "mainPanel", components: [
996           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
997           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
998             classes: "in-panel", components: [
999             {kind: "XV.InputWidget", attr: "name", name: "name"},
1000             {kind: "XV.InputWidget", attr: "description", name: "description" },
1001             {kind: "XV.FileInput", name: "file", attr: "data"}
1002           ]}
1003         ]}
1004       ]}
1005     ],
1006
1007     /**
1008       When a file is uploaded we want the filename to overwrite
1009       the name and description fields.
1010      */
1011     controlValueChanged: function (inSender, inEvent) {
1012       var filename = inEvent.filename;
1013       this.inherited(arguments);
1014
1015       if (filename) {
1016         this.$.name.setValue(filename);
1017         this.$.description.setValue(filename);
1018       }
1019     },
1020     /**
1021       We want the description to be always disabled, which means we have
1022       to go in after the attributesChanged method, which, as it's defined
1023       in the superkind, will reset the disabled status based on permissions etc.
1024      */
1025     attributesChanged: function (model, options) {
1026       this.inherited(arguments);
1027       this.$.description.setDisabled(true);
1028     }
1029   });
1030
1031   XV.registerModelWorkspace("XM.FileRelation", "XV.FileWorkspace");
1032
1033   // ..........................................................
1034   // FREIGHT CLASS
1035   //
1036
1037   enyo.kind({
1038     name: "XV.FreightClassWorkspace",
1039     kind: "XV.Workspace",
1040     title: "_freightClass".loc(),
1041     model: "XM.FreightClass",
1042     components: [
1043       {kind: "Panels", arrangerKind: "CarouselArranger",
1044         fit: true, components: [
1045         {kind: "XV.Groupbox", name: "mainPanel", components: [
1046           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1047           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1048             classes: "in-panel", components: [
1049             {kind: "XV.InputWidget", attr: "code"},
1050             {kind: "XV.InputWidget", attr: "description"}
1051           ]}
1052         ]}
1053       ]}
1054     ]
1055   });
1056
1057   XV.registerModelWorkspace("XM.FreightClass", "XV.FreightClassWorkspace");
1058
1059   // ..........................................................
1060   // HONORIFIC
1061   //
1062
1063   enyo.kind({
1064     name: "XV.HonorificWorkspace",
1065     kind: "XV.Workspace",
1066     title: "_honorific".loc(),
1067     model: "XM.Honorific",
1068     components: [
1069       {kind: "Panels", arrangerKind: "CarouselArranger",
1070         fit: true, components: [
1071         {kind: "XV.Groupbox", name: "mainPanel", components: [
1072           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1073           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1074             classes: "in-panel", components: [
1075             {kind: "XV.InputWidget", attr: "code"}
1076           ]}
1077         ]}
1078       ]}
1079     ]
1080   });
1081
1082   XV.registerModelWorkspace("XM.Honorific", "XV.HonorificWorkspace");
1083
1084   // ..........................................................
1085   // INCIDENT
1086   //
1087
1088   var incidentHash = {
1089     name: "XV.IncidentWorkspace",
1090     kind: "XV.Workspace",
1091     title: "_incident".loc(),
1092     headerAttrs: ["number", "-", "description"],
1093     model: "XM.Incident",
1094     components: [
1095       {kind: "Panels", arrangerKind: "CarouselArranger",
1096         fit: true, components: [
1097         {kind: "XV.Groupbox", name: "mainPanel", components: [
1098           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1099           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
1100             classes: "in-panel", components: [
1101             {kind: "XV.InputWidget", attr: "number"},
1102             {kind: "XV.InputWidget", attr: "description"},
1103             {kind: "XV.CheckboxWidget", attr: "isPublic", name: "isPublic"},
1104             {kind: "XV.AccountWidget", attr: "account"},
1105             {kind: "XV.ContactWidget", attr: "contact"},
1106             {kind: "XV.IncidentCategoryPicker", attr: "category"},
1107             {kind: "onyx.GroupboxHeader", content: "_status".loc()},
1108             {kind: "XV.IncidentStatusPicker", attr: "status"},
1109             {kind: "XV.PriorityPicker", attr: "priority"},
1110             {kind: "XV.IncidentSeverityPicker", attr: "severity"},
1111             {kind: "XV.IncidentResolutionPicker", attr: "resolution"},
1112             {kind: "onyx.GroupboxHeader", content: "_userAccounts".loc()},
1113             {kind: "XV.UserAccountWidget", attr: "owner"},
1114             {kind: "XV.UserAccountWidget", attr: "assignedTo"},
1115             {kind: "XV.IncidentCharacteristicsWidget", attr: "characteristics"},
1116             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1117             {kind: "XV.TextArea", attr: "notes", fit: true},
1118             {kind: "onyx.GroupboxHeader", content: "_relationships".loc()},
1119             {kind: "XV.ItemWidget", attr: "item"}
1120           ]}
1121         ]},
1122         {kind: "XV.IncidentCommentBox", attr: "comments"},
1123         {kind: "XV.IncidentDocumentsBox", attr: "documents"},
1124         {kind: "XV.IncidentHistoryRelationsBox", attr: "history"}
1125       ]}
1126     ],
1127     create: function () {
1128       this.inherited(arguments);
1129       var settings = XT.session.getSettings();
1130       this.$.isPublic.setShowing(settings.get('IncidentsPublicPrivate'));
1131     }
1132   };
1133
1134   incidentHash = enyo.mixin(incidentHash, XV.accountNotifyContactMixin);
1135   enyo.kind(incidentHash);
1136
1137   XV.registerModelWorkspace("XM.Incident", "XV.IncidentWorkspace");
1138   XV.registerModelWorkspace("XM.IncidentRelation", "XV.IncidentWorkspace");
1139   XV.registerModelWorkspace("XM.IncidentListItem", "XV.IncidentWorkspace");
1140
1141   // ..........................................................
1142   // INCIDENT EMAIL PROFILE
1143   //
1144
1145   enyo.kind({
1146     name: "XV.IncidentEmailProfileWorkspace",
1147     kind: "XV.EmailProfileWorkspace",
1148     title: "_incidentEmailProfile".loc(),
1149     model: "XM.IncidentEmailProfile",
1150   });
1151
1152   XV.registerModelWorkspace("XM.IncidentEmailProfile", "XV.IncidentEmailProfileWorkspace");
1153
1154   // ..........................................................
1155   // INCIDENT CATEGORY
1156   //
1157
1158   enyo.kind({
1159     name: "XV.IncidentCategoryWorkspace",
1160     kind: "XV.OrderedReferenceWorkspace",
1161     title: "_incidentCategory".loc(),
1162     model: "XM.IncidentCategory",
1163     components: [
1164       {kind: "Panels", arrangerKind: "CarouselArranger",
1165         fit: true, components: [
1166         {kind: "XV.Groupbox", name: "mainPanel", components: [
1167           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1168           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1169             classes: "in-panel", components: [
1170             {kind: "XV.InputWidget", attr: "name"},
1171             {kind: "XV.InputWidget", attr: "description"},
1172             {kind: "XV.NumberWidget", attr: "order"},
1173             {kind: "XV.IncidentEmailProfilePicker", attr: "emailProfile"}
1174           ]}
1175         ]}
1176       ]}
1177     ]
1178   });
1179
1180   XV.registerModelWorkspace("XM.IncidentCategory", "XV.IncidentCategoryWorkspace");
1181
1182   // ..........................................................
1183   // INCIDENT RESOLUTION
1184   //
1185
1186   enyo.kind({
1187     name: "XV.IncidentResolutionWorkspace",
1188     kind: "XV.OrderedReferenceWorkspace",
1189     title: "_incidentResolution".loc(),
1190     model: "XM.IncidentResolution"
1191   });
1192
1193   XV.registerModelWorkspace("XM.IncidentResolution", "XV.IncidentResolutionWorkspace");
1194
1195   // ..........................................................
1196   // INCIDENT SEVERITY
1197   //
1198
1199   enyo.kind({
1200     name: "XV.IncidentSeverityWorkspace",
1201     kind: "XV.OrderedReferenceWorkspace",
1202     title: "_incidentSeverity".loc(),
1203     model: "XM.IncidentSeverity"
1204   });
1205
1206   XV.registerModelWorkspace("XM.IncidentSeverity", "XV.IncidentSeverityWorkspace");
1207
1208   // ..........................................................
1209   // INVOICE
1210   //
1211   hash = {
1212     name: "XV.InvoiceWorkspace",
1213     kind: "XV.Workspace",
1214     title: "_invoice".loc(),
1215     model: "XM.Invoice",
1216     actions: [{
1217       name: "print",
1218       isViewMethod: true,
1219       label: "_print".loc(),
1220       privilege: "PrintInvoices",
1221       prerequisite: "isReadyClean"
1222     }],
1223     components: [
1224       {kind: "Panels", arrangerKind: "CarouselArranger",
1225         fit: true, components: [
1226         {kind: "XV.Groupbox", name: "mainPanel", components: [
1227           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1228           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1229               classes: "in-panel", fit: true, components: [
1230             {name: "mainSubgroup", components: [ // not a scroller, so we can addBefore
1231               {kind: "XV.InputWidget", attr: "number"},
1232               {kind: "XV.DateWidget", attr: "invoiceDate"},
1233               {kind: "XV.CheckboxWidget", name: "isPosted", attr: "isPosted"},
1234               {kind: "XV.CheckboxWidget", name: "isVoid", attr: "isVoid"},
1235               {kind: "onyx.GroupboxHeader", content: "_billTo".loc()},
1236               {kind: "XV.BillingCustomerWidget", attr: "customer",
1237                  name: "customerWidget", showAddress: true,
1238                  label: "_customer".loc(), nameAttribute: ""
1239               },
1240               {kind: "XV.AddressFieldsWidget",
1241                 name: "addressWidget", attr:
1242                 {name: "billtoName", line1: "billtoAddress1",
1243                   line2: "billtoAddress2", line3: "billtoAddress3",
1244                   city: "billtoCity", state: "billtoState",
1245                   postalCode: "billtoPostalCode", country: "billtoCountry"}
1246               },
1247               {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1248               {kind: "XV.TextArea", attr: "notes", fit: true}
1249             ]}
1250           ]}
1251         ]},
1252         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(),
1253           components: [
1254           {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
1255           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
1256             classes: "in-panel", components: [
1257             {kind: "XV.CurrencyPicker", attr: "currency"},
1258             {kind: "XV.BillingTermsPicker", attr: "terms"},
1259             {kind: "XV.SalesRepPicker", attr: "salesRep"},
1260             {kind: "XV.PercentWidget", attr: "commission"},
1261             {kind: "XV.SaleTypePicker", attr: "saleType"},
1262             {kind: "XV.InputWidget", attr: "customerPurchaseOrderNumber",
1263               label: "_custPO".loc()},
1264             {kind: "XV.TaxZonePicker", attr: "taxZone"},
1265           ]}
1266         ]},
1267         {kind: "XV.InvoiceAllocationsBox", attr: "allocations", title: "_allocatedCredit".loc()},
1268         // TODO: nest the next two items in a groupbox
1269         {kind: "XV.InvoiceTaxBox", attr: "taxes", title: "_taxes".loc()},
1270         {kind: "XV.InvoiceTaxAdjustmentBox", attr: "taxAdjustments", title: "_taxAdjustments".loc()},
1271         {kind: "XV.InvoiceDocumentsBox", attr: "documents"}
1272       ]}
1273     ],
1274     create: function () {
1275       this.inherited(arguments);
1276       if (enyo.platform.touch) {
1277         this.$.panels.createComponents([
1278           {kind: "XV.InvoiceLineItemBox", name: "invoiceLineItemBox", attr: "lineItems",
1279             title: "_lineItems".loc(), addBefore: this.$.settingsPanel, classes: "medium-panel"}
1280         ], {owner: this});
1281       } else {
1282         this.$.panels.createComponents([
1283           {kind: "XV.InvoiceLineItemGridBox", name: "invoiceLineItemBox", title: "_lineItems".loc(),
1284             attr: "lineItems", addBefore: this.$.settingsPanel}
1285         ], {owner: this});
1286       }
1287       this.processExtensions(true);
1288     }
1289   };
1290   hash = enyo.mixin(hash, XV.WorkspaceAddressMixin);
1291   enyo.kind(hash);
1292
1293   XV.registerModelWorkspace("XM.InvoiceListItem", "XV.InvoiceWorkspace");
1294
1295   enyo.kind({
1296     name: "XV.InvoiceLineWorkspace",
1297     kind: "XV.ChildWorkspace",
1298     title: "_invoiceLine".loc(),
1299     model: "XM.InvoiceLine",
1300     published: {
1301       currencyKey: "invoice.currency",
1302       effectiveKey: "invoice.invoiceDate"
1303     },
1304     components: [
1305       {kind: "Panels", arrangerKind: "CarouselArranger",
1306         fit: true, components: [
1307         {kind: "XV.Groupbox", name: "mainPanel", components: [
1308           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1309           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1310             classes: "in-panel", fit: true, components: [
1311             {kind: "XV.NumberWidget", attr: "lineNumber"},
1312             {kind: "XV.CheckboxWidget", attr: "isMiscellaneous"},
1313             {kind: "XV.ItemSiteWidget", attr: {item: "item", site: "site"},
1314               name: "itemSiteWidget",
1315               query: {parameters: [
1316               {attribute: "item.isSold", value: true},
1317               {attribute: "item.isActive", value: true},
1318               {attribute: "isSold", value: true},
1319               {attribute: "isActive", value: true}
1320             ]}},
1321             {kind: "XV.SalesPriceWidget", attr: "item.listPrice", label: "_listPrice".loc()},
1322             {kind: "XV.SalesPriceWidget", attr: "item.wholesalePrice",
1323               label: "_wholesalePrice".loc()},
1324             {kind: "XV.InputWidget", attr: "customerPartNumber"},
1325             {kind: "XV.InputWidget", attr: "itemNumber"},
1326             {kind: "XV.InputWidget", attr: "itemDescription"},
1327             {kind: "XV.SalesCategoryPicker", attr: "salesCategory"},
1328           ]}
1329         ]},
1330         {kind: "XV.Groupbox", name: "pricePanel", title: "_price".loc(), components: [
1331           {kind: "onyx.GroupboxHeader", content: "_price".loc()},
1332           {kind: "XV.ScrollableGroupbox", name: "priceGroup",
1333               classes: "in-panel", fit: true, components: [
1334             {kind: "XV.QuantityWidget", attr: "quantity", label: "_ordered".loc()},
1335             {kind: "XV.QuantityWidget", attr: "billed"},
1336             {kind: "XV.UnitPicker", name: "quantityUnitPicker",
1337               attr: "quantityUnit"},
1338             {kind: "XV.MoneyWidget", attr:
1339               {localValue: "price", currency: ""},
1340               label: "_price".loc(), currencyDisabled: true,
1341               scale: XT.SALES_PRICE_SCALE},
1342             {kind: "XV.UnitPicker", name: "priceUnitPicker",
1343               attr: "priceUnit"},
1344             {kind: "XV.MoneyWidget", attr:
1345               {localValue: "extendedPrice", currency: ""},
1346               label: "_extendedPrice".loc(), currencyDisabled: true,
1347               scale: XT.EXTENDED_PRICE_SCALE}
1348           ]}
1349         ]},
1350         {kind: "XV.Groupbox", name: "detailsPanel", title: "_detail".loc(),
1351           components: [
1352           {kind: "onyx.GroupboxHeader", content: "_detail".loc()},
1353           {kind: "XV.ScrollableGroupbox", name: "detailGroup",
1354             classes: "in-panel", fit: true, components: [
1355             {kind: "XV.MoneyWidget", attr: {baseValue: "item.standardCost"},
1356               label: "_unitCost".loc(), isEditableProperty: "baseValue",
1357               currencyDisabled: true},
1358             {kind: "XV.MoneyWidget", attr: {localValue: "customerPrice"},
1359               label: "_customerPrice".loc(), scale: XT.SALES_PRICE_SCALE,
1360               currencyDisabled: true},
1361             {kind: "onyx.GroupboxHeader", content: "_tax".loc()},
1362             {kind: "XV.TaxTypePicker", attr: "taxType"},
1363             {kind: "XV.MoneyWidget", attr: {localValue: "taxTotal"},
1364               label: "_tax".loc(), currencyDisabled: true},
1365             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1366             {kind: "XV.TextArea", attr: "notes", fit: true}
1367           ]}
1368         ]},
1369         {kind: "XV.InvoiceLineTaxBox", attr: "taxes"}
1370       ]}
1371     ],
1372     create: function () {
1373       this.inherited(arguments);
1374       var effectiveKey = this.getEffectiveKey(),
1375         currencyKey = this.getCurrencyKey();
1376
1377       // Set currency and effective attributes on money widgets
1378       this.getComponents().forEach(function (ctl) {
1379         if (ctl.kind === "XV.MoneyWidget") {
1380           ctl.attr.currency = currencyKey;
1381           ctl.attr.effective = effectiveKey;
1382         }
1383       });
1384     }
1385   });
1386   // ..........................................................
1387   // INVOICE ALLOCATION
1388   //
1389
1390   /*
1391   enyo.kind({
1392     name: "XV.InvoiceAllocationWorkspace",
1393     kind: "XV.Workspace",
1394     title: "_allocation".loc(),
1395     model: "XM.InvoiceAllocation",
1396     components: [
1397       {kind: "Panels", arrangerKind: "CarouselArranger",
1398         fit: true, components: [
1399         {kind: "XV.Groupbox", name: "mainPanel", components: [
1400           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1401           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1402             classes: "in-panel", components: [
1403             {kind: "XV.InputWidget", attr: "code"}
1404           ]}
1405         ]}
1406       ]}
1407     ]
1408   });
1409
1410   XV.registerModelWorkspace("XM.InvoiceAllocation", "XV.InvoiceAllocationWorkspace");
1411   */
1412   // ..........................................................
1413   // ITEM
1414   //
1415
1416   enyo.kind({
1417     name: "XV.ItemWorkspace",
1418     kind: "XV.Workspace",
1419     title: "_item".loc(),
1420     model: "XM.Item",
1421     headerAttrs: ["number", "-", "description1"],
1422     components: [
1423       {kind: "Panels", arrangerKind: "CarouselArranger",
1424         fit: true, components: [
1425         {kind: "XV.Groupbox", name: "mainPanel", components: [
1426           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1427           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
1428             classes: "in-panel", components: [
1429             {kind: "XV.InputWidget", attr: "number"},
1430             {kind: "XV.CheckboxWidget", attr: "isActive"},
1431             {kind: "XV.InputWidget", attr: "description1"},
1432             {kind: "XV.InputWidget", attr: "description2"},
1433             {kind: "XV.ItemTypePicker", attr: "itemType", showNone: false},
1434             {kind: "XV.ClassCodePicker", attr: "classCode"},
1435             {kind: "XV.UnitPicker", attr: "inventoryUnit"},
1436             {kind: "XV.CheckboxWidget", attr: "isFractional"},
1437             {kind: "XV.ItemCharacteristicsWidget", attr: "characteristics"},
1438             {kind: "onyx.GroupboxHeader",
1439               content: "_extendedDescription".loc()},
1440             {kind: "XV.TextArea", attr: "extendedDescription"},
1441             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1442             {kind: "XV.TextArea", attr: "notes", fit: true}
1443           ]}
1444         ]},
1445         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(),
1446           components: [
1447           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
1448             classes: "in-panel", components: [
1449             {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
1450             {kind: "XV.CheckboxWidget", attr: "isSold"},
1451             {kind: "XV.ProductCategoryPicker", attr: "productCategory",
1452               label: "_category".loc()},
1453             {kind: "XV.SalesPriceWidget", attr: "listPrice"},
1454             {kind: "XV.SalesPriceWidget", attr: "wholesalePrice"},
1455             {kind: "XV.UnitPicker", attr: "priceUnit"},
1456             {kind: "XV.CheckboxWidget", attr: "isExclusive"}
1457           ]}
1458         ]},
1459         {kind: "XV.ItemCommentBox", attr: "comments"},
1460         {kind: "XV.ItemDocumentsBox", attr: "documents"},
1461         {kind: "XV.ItemAliasBox", attr: "aliases"}
1462       ]}
1463     ]
1464   });
1465
1466   XV.registerModelWorkspace("XM.ItemRelation", "XV.ItemWorkspace");
1467   XV.registerModelWorkspace("XM.ItemListItem", "XV.ItemWorkspace");
1468
1469   // ..........................................................
1470   // ITEM GROUP
1471   //
1472
1473   enyo.kind({
1474     name: "XV.ItemGroupWorkspace",
1475     kind: "XV.Workspace",
1476     title: "_itemGroup".loc(),
1477     model: "XM.ItemGroup",
1478     components: [
1479       {kind: "Panels", arrangerKind: "CarouselArranger",
1480         fit: true, components: [
1481         {kind: "XV.Groupbox", name: "mainPanel", components: [
1482           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1483           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1484             classes: "in-panel", components: [
1485             {kind: "XV.InputWidget", attr: "name"},
1486             {kind: "XV.InputWidget", attr: "description"}
1487           ]}
1488         ]},
1489         {kind: "XV.ItemGroupItemBox", attr: "items"}
1490       ]}
1491     ]
1492   });
1493
1494   XV.registerModelWorkspace("XM.ItemGroup", "XV.ItemGroupWorkspace");
1495   XV.registerModelWorkspace("XM.ItemGroupRelation", "XV.ItemGroupWorkspace");
1496   XV.registerModelWorkspace("XM.ItemGroupItem", "XV.ItemGroupWorkspace");
1497
1498   // ..........................................................
1499   // ITEM SITE
1500   //
1501
1502   enyo.kind({
1503     name: "XV.ItemSiteWorkspace",
1504     kind: "XV.Workspace",
1505     title: "_itemSite".loc(),
1506     model: "XM.ItemSite",
1507     headerAttrs: ["item.number", "-", "site.code"],
1508     components: [
1509       {kind: "Panels", arrangerKind: "CarouselArranger",
1510         fit: true, components: [
1511         {kind: "XV.Groupbox", name: "mainPanel", components: [
1512           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1513           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
1514             classes: "in-panel", components: [
1515             {kind: "XV.ItemWidget", attr: "item"},
1516             {kind: "XV.OptionalSitePicker", attr: "site"},
1517             {kind: "XV.CheckboxWidget", attr: "isActive"},
1518             {kind: "XV.PlannerCodePicker", attr: "plannerCode"},
1519             {kind: "XV.CostCategoryPicker", attr: "costCategory"},
1520             {kind: "XV.CheckboxWidget", attr: "isSold"},
1521             {kind: "XV.NumberSpinnerWidget", attr: "soldRanking"},
1522             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1523             {kind: "XV.TextArea", attr: "notes", fit: true}
1524           ]}
1525         ]},
1526         {kind: "XV.ItemSiteCommentBox", attr: "comments"}
1527       ]}
1528     ]
1529   });
1530
1531   XV.registerModelWorkspace("XM.ItemSiteRelation", "XV.ItemSiteWorkspace");
1532   XV.registerModelWorkspace("XM.ItemItemSiteRelation", "XV.ItemSiteWorkspace");
1533   XV.registerModelWorkspace("XM.ItemSiteListItem", "XV.ItemSiteWorkspace");
1534
1535   // ..........................................................
1536   // OPPORTUNITY
1537   //
1538
1539   var opportunityHash = {
1540     name: "XV.OpportunityWorkspace",
1541     kind: "XV.Workspace",
1542     title: "_opportunity".loc(),
1543     headerAttrs: ["number", "-", "name"],
1544     model: "XM.Opportunity",
1545     components: [
1546       {kind: "Panels", arrangerKind: "CarouselArranger",
1547         fit: true, components: [
1548         {kind: "XV.Groupbox", name: "mainPanel", components: [
1549           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1550           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
1551             classes: "in-panel", components: [
1552             {kind: "XV.InputWidget", attr: "number"},
1553             {kind: "XV.CheckboxWidget", attr: "isActive"},
1554             {kind: "XV.InputWidget", attr: "name"},
1555             {kind: "XV.AccountWidget", attr: "account"},
1556             {kind: "XV.ContactWidget", attr: "contact"},
1557             {kind: "XV.MoneyWidget",
1558               attr: {localValue: "amount", currency: "currency"},
1559               label: "_amount".loc()},
1560             {kind: "XV.NumberWidget", attr: "probability"},
1561             {kind: "onyx.GroupboxHeader", content: "_status".loc()},
1562             {kind: "XV.OpportunityStagePicker", attr: "opportunityStage",
1563               label: "_stage".loc()},
1564             {kind: "XV.PriorityPicker", attr: "priority"},
1565             {kind: "XV.OpportunityTypePicker", attr: "opportunityType",
1566               label: "_type".loc()},
1567             {kind: "XV.OpportunitySourcePicker", attr: "opportunitySource",
1568               label: "_source".loc()},
1569             {kind: "onyx.GroupboxHeader", content: "_schedule".loc()},
1570             {kind: "XV.DateWidget", attr: "targetClose"},
1571             {kind: "XV.DateWidget", attr: "startDate"},
1572             {kind: "XV.DateWidget", attr: "assignDate"},
1573             {kind: "XV.DateWidget", attr: "actualClose"},
1574             {kind: "onyx.GroupboxHeader", content: "_userAccounts".loc()},
1575             {kind: "XV.UserAccountWidget", attr: "owner"},
1576             {kind: "XV.UserAccountWidget", attr: "assignedTo"},
1577             {kind: "XV.OpportunityCharacteristicsWidget", attr: "characteristics"},
1578             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1579             {kind: "XV.TextArea", attr: "notes", fit: true}
1580           ]}
1581         ]},
1582         {kind: "XV.OpportunityCommentBox", attr: "comments"},
1583         {kind: "XV.OpportunityDocumentsBox", attr: "documents"}
1584       ]}
1585     ]
1586   };
1587
1588   opportunityHash = enyo.mixin(opportunityHash, XV.accountNotifyContactMixin);
1589   enyo.kind(opportunityHash);
1590
1591   XV.registerModelWorkspace("XM.Opportunity", "XV.OpportunityWorkspace");
1592   XV.registerModelWorkspace("XM.OpportunityRelation", "XV.OpportunityWorkspace");
1593   XV.registerModelWorkspace("XM.OpportunityListItem", "XV.OpportunityWorkspace");
1594
1595   // ..........................................................
1596   // OPPORTUNITY SOURCE
1597   //
1598
1599   enyo.kind({
1600     name: "XV.OpportunitySourceWorkspace",
1601     kind: "XV.Workspace",
1602     title: "_opportunitySource".loc(),
1603     model: "XM.OpportunitySource"
1604   });
1605
1606   XV.registerModelWorkspace("XM.OpportunitySource", "XV.OpportunitySourceWorkspace");
1607
1608   // ..........................................................
1609   // OPPORTUNITY STAGE
1610   //
1611
1612   enyo.kind({
1613     name: "XV.OpportunityStageWorkspace",
1614     kind: "XV.Workspace",
1615     title: "_opportunityStage".loc(),
1616     model: "XM.OpportunityStage",
1617     components: [
1618       {kind: "Panels", arrangerKind: "CarouselArranger",
1619         fit: true, components: [
1620         {kind: "XV.Groupbox", name: "mainPanel", components: [
1621           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1622           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1623             classes: "in-panel", components: [
1624             {kind: "XV.InputWidget", attr: "name"},
1625             {kind: "XV.InputWidget", attr: "description"},
1626             {kind: "XV.CheckboxWidget", attr: "deactivate"}
1627           ]}
1628         ]}
1629       ]}
1630     ]
1631   });
1632
1633   XV.registerModelWorkspace("XM.OpportunityStage", "XV.OpportunityStageWorkspace");
1634
1635   // ..........................................................
1636   // OPPORTUNITY TYPE
1637   //
1638
1639   enyo.kind({
1640     name: "XV.OpportunityTypeWorkspace",
1641     kind: "XV.Workspace",
1642     title: "_opportunityType".loc(),
1643     model: "XM.OpportunityType"
1644   });
1645
1646   XV.registerModelWorkspace("XM.OpportunityType", "XV.OpportunityTypeWorkspace");
1647
1648   // ..........................................................
1649   // PLANNER CODE
1650   //
1651
1652   enyo.kind({
1653     name: "XV.PlannerCodeWorkspace",
1654     kind: "XV.Workspace",
1655     title: "_plannerCode".loc(),
1656     model: "XM.PlannerCode",
1657     components: [
1658       {kind: "Panels", arrangerKind: "CarouselArranger",
1659         fit: true, components: [
1660         {kind: "XV.Groupbox", name: "mainPanel", components: [
1661           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1662           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1663             classes: "in-panel", components: [
1664             {kind: "XV.InputWidget", attr: "code"},
1665             {kind: "XV.InputWidget", attr: "name"}
1666           ]}
1667         ]}
1668       ]}
1669     ]
1670   });
1671
1672   XV.registerModelWorkspace("XM.PlannerCode", "XV.PlannerCodeWorkspace");
1673
1674   // ..........................................................
1675   // PRIORITY
1676   //
1677
1678   enyo.kind({
1679     name: "XV.PriorityWorkspace",
1680     kind: "XV.OrderedReferenceWorkspace",
1681     title: "_priority".loc(),
1682     model: "XM.Priority"
1683   });
1684
1685   XV.registerModelWorkspace("XM.Priority", "XV.PriorityWorkspace");
1686
1687   // ..........................................................
1688   // PRODUCT CATEGORY
1689   //
1690
1691   enyo.kind({
1692     name: "XV.ProductCategoryWorkspace",
1693     kind: "XV.Workspace",
1694     title: "_productCategory".loc(),
1695     model: "XM.ProductCategory",
1696     components: [
1697       {kind: "Panels", arrangerKind: "CarouselArranger",
1698         fit: true, components: [
1699         {kind: "XV.Groupbox", name: "mainPanel", components: [
1700           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1701           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1702             classes: "in-panel", components: [
1703             {kind: "XV.InputWidget", attr: "code"},
1704             {kind: "XV.InputWidget", attr: "description"}
1705           ]}
1706         ]}
1707       ]}
1708     ]
1709   });
1710
1711   XV.registerModelWorkspace("XM.ProductCategory", "XV.ProductCategoryWorkspace");
1712
1713   // ..........................................................
1714   // PROSPECT
1715   //
1716
1717   enyo.kind({
1718     name: "XV.ProspectWorkspace",
1719     kind: "XV.AccountDocumentWorkspace",
1720     title: "_prospect".loc(),
1721     model: "XM.Prospect",
1722     headerAttrs: ["number", "-", "name"],
1723     components: [
1724       {kind: "Panels", arrangerKind: "CarouselArranger",
1725         fit: true, components: [
1726         {kind: "XV.Groupbox", name: "mainPanel", components: [
1727           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1728           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
1729             classes: "in-panel", components: [
1730             {kind: "XV.InputWidget", attr: "number"},
1731             {kind: "XV.InputWidget", attr: "name"},
1732             {kind: "XV.CheckboxWidget", attr: "isActive"},
1733             {kind: "XV.SalesRepPicker", attr: "salesRep"},
1734             {kind: "XV.TaxZonePicker", attr: "taxZone"},
1735             {kind: "onyx.GroupboxHeader", content: "_contact".loc()},
1736             {kind: "XV.ContactWidget", attr: "contact",
1737               showAddress: true, label: "_name".loc()},
1738             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1739             {kind: "XV.TextArea", attr: "notes"}
1740           ]}
1741         ]},
1742         {kind: "XV.ProspectQuoteListRelationsBox", attr: "quoteRelations"}
1743       ]},
1744       // TODO: use standard notify mechanism
1745       {kind: "onyx.Popup", name: "findExistingAccountPopup", centered: true,
1746         modal: true, floating: true, scrim: true, onShow: "popupShown",
1747         onHide: "popupHidden", components: [
1748         {content: "_accountExists".loc()},
1749         {name: "whatToDo", content: "_convertAccountProspect".loc()},
1750         {tag: "br"},
1751         {kind: "onyx.Button", name: "convert", content: "_ok".loc(), ontap: "accountConvert",
1752           classes: "onyx-blue xv-popup-button"},
1753         {kind: "onyx.Button", name: "cancel", content: "_cancel".loc(), ontap: "accountCancel",
1754           classes: "xv-popup-button"}
1755       ]}
1756     ]
1757   });
1758
1759   XV.registerModelWorkspace("XM.ProspectRelation", "XV.ProspectWorkspace");
1760   XV.registerModelWorkspace("XM.ProspectListItem", "XV.ProspectWorkspace");
1761
1762   // ..........................................................
1763   // RETURN
1764   //
1765   hash = {
1766     name: "XV.ReturnWorkspace",
1767     kind: "XV.Workspace",
1768     title: "_return".loc(),
1769     model: "XM.Return",
1770     components: [
1771       {kind: "Panels", arrangerKind: "CarouselArranger",
1772         fit: true, components: [
1773         {kind: "XV.Groupbox", name: "mainPanel", components: [
1774           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1775           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1776               classes: "in-panel", fit: true, components: [
1777             {name: "mainSubgroup", components: [ // not a scroller, so we can addBefore
1778               {kind: "XV.InputWidget", attr: "number"},
1779               {kind: "XV.DateWidget", attr: "returnDate"},
1780               {kind: "XV.CheckboxWidget", name: "isPosted", attr: "isPosted"},
1781               {kind: "XV.CheckboxWidget", name: "isVoid", attr: "isVoid"},
1782               {kind: "onyx.GroupboxHeader", content: "_billTo".loc()},
1783               {kind: "XV.BillingCustomerWidget", attr: "customer",
1784                  name: "customerWidget", showAddress: true,
1785                  label: "_customer".loc(), nameAttribute: ""
1786               },
1787               {kind: "XV.AddressFieldsWidget",
1788                 name: "addressWidget", attr:
1789                 {name: "billtoName", line1: "billtoAddress1",
1790                   line2: "billtoAddress2", line3: "billtoAddress3",
1791                   city: "billtoCity", state: "billtoState",
1792                   postalCode: "billtoPostalCode", country: "billtoCountry"}
1793               },
1794               {kind: "onyx.GroupboxHeader", content: "_notes".loc(), name: "notesHeader"},
1795               {kind: "XV.TextArea", attr: "notes", fit: true}
1796             ]}
1797           ]}
1798         ]},
1799         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(),
1800           components: [
1801           {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
1802           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
1803             classes: "in-panel", components: [
1804             {kind: "XV.CurrencyPicker", attr: "currency"},
1805             {kind: "XV.SalesRepPicker", attr: "salesRep"},
1806             {kind: "XV.PercentWidget", attr: "commission"},
1807             {kind: "XV.SaleTypePicker", attr: "saleType"},
1808             {kind: "XV.InputWidget", attr: "customerPurchaseOrderNumber",
1809               label: "_custPO".loc()},
1810             {kind: "XV.TaxZonePicker", attr: "taxZone"},
1811           ]}
1812         ]},
1813         //{kind: "XV.ReturnAllocationsBox", attr: "allocations", title: "_allocatedCredit".loc()},
1814         // TODO: nest the next two items in a groupbox
1815         {kind: "XV.ReturnTaxBox", attr: "taxes", title: "_taxes".loc()},
1816         {kind: "XV.ReturnTaxAdjustmentBox", attr: "taxAdjustments", title: "_taxAdjustments".loc()}
1817         //{kind: "XV.ReturnDocumentsBox", attr: "documents"}
1818       ]}
1819     ],
1820     create: function () {
1821       this.inherited(arguments);
1822       if (enyo.platform.touch) {
1823         this.$.panels.createComponents([
1824           {kind: "XV.ReturnLineItemBox", name: "returnLineItemBox",
1825             attr: "lineItems", title: "_lineItems".loc(),
1826               addBefore: this.$.settingsPanel, classes: "medium-panel"}
1827         ], {owner: this});
1828       } else {
1829         this.$.panels.createComponents([
1830           {kind: "XV.ReturnLineItemGridBox", name: "returnLineItemBox",
1831             title: "_lineItems".loc(), attr: "lineItems", addBefore: this.$.settingsPanel}
1832         ], {owner: this});
1833       }
1834       this.processExtensions(true);
1835     }
1836   };
1837   hash = enyo.mixin(hash, XV.WorkspaceAddressMixin);
1838   enyo.kind(hash);
1839
1840   XV.registerModelWorkspace("XM.ReturnListItem", "XV.ReturnWorkspace");
1841
1842   enyo.kind({
1843     name: "XV.ReturnLineWorkspace",
1844     kind: "XV.ChildWorkspace",
1845     title: "_returnLine".loc(),
1846     model: "XM.ReturnLine",
1847     published: {
1848       currencyKey: "return.currency",
1849       effectiveKey: "return.returnDate"
1850     },
1851     components: [
1852       {kind: "Panels", arrangerKind: "CarouselArranger",
1853         fit: true, components: [
1854         {kind: "XV.Groupbox", name: "mainPanel", components: [
1855           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
1856           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
1857             classes: "in-panel", fit: true, components: [
1858             {kind: "XV.NumberWidget", attr: "lineNumber"},
1859             {kind: "XV.ItemSiteWidget", attr: {item: "item", site: "site"},
1860               name: "itemSiteWidget",
1861               query: {parameters: [
1862               {attribute: "item.isSold", value: true},
1863               {attribute: "item.isActive", value: true},
1864               {attribute: "isSold", value: true},
1865               {attribute: "isActive", value: true}
1866             ]}},
1867             {kind: "XV.SalesPriceWidget", attr: "item.listPrice", label: "_listPrice".loc()},
1868             {kind: "XV.SalesPriceWidget", attr: "item.wholesalePrice",
1869               label: "_wholesalePrice".loc()}
1870           ]}
1871         ]},
1872         {kind: "XV.Groupbox", name: "pricePanel", title: "_price".loc(), components: [
1873           {kind: "onyx.GroupboxHeader", content: "_price".loc()},
1874           {kind: "XV.ScrollableGroupbox", name: "priceGroup",
1875               classes: "in-panel", fit: true, components: [
1876             {kind: "XV.QuantityWidget", attr: "quantity", label: "_ordered".loc()},
1877             {kind: "XV.QuantityWidget", attr: "credited"},
1878             {kind: "XV.UnitPicker", name: "quantityUnitPicker",
1879               attr: "quantityUnit"},
1880             {kind: "XV.MoneyWidget", attr:
1881               {localValue: "price", currency: ""},
1882               label: "_price".loc(), currencyDisabled: true,
1883               scale: XT.SALES_PRICE_SCALE},
1884             {kind: "XV.UnitPicker", name: "priceUnitPicker",
1885               attr: "priceUnit"},
1886             {kind: "XV.MoneyWidget", attr:
1887               {localValue: "extendedPrice", currency: ""},
1888               label: "_extendedPrice".loc(), currencyDisabled: true,
1889               scale: XT.EXTENDED_PRICE_SCALE}
1890           ]}
1891         ]},
1892         {kind: "XV.Groupbox", name: "detailsPanel", title: "_detail".loc(),
1893           components: [
1894           {kind: "onyx.GroupboxHeader", content: "_detail".loc()},
1895           {kind: "XV.ScrollableGroupbox", name: "detailGroup",
1896             classes: "in-panel", fit: true, components: [
1897             {kind: "XV.MoneyWidget", attr: {baseValue: "item.standardCost"},
1898               label: "_unitCost".loc(), isEditableProperty: "baseValue",
1899               currencyDisabled: true},
1900             {kind: "onyx.GroupboxHeader", content: "_tax".loc()},
1901             {kind: "XV.TaxTypePicker", attr: "taxType"},
1902             {kind: "XV.MoneyWidget", attr: {localValue: "taxTotal"},
1903               label: "_taxTotal".loc(), currencyDisabled: true},
1904             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
1905             {kind: "XV.TextArea", attr: "notes", fit: true}
1906           ]}
1907         ]},
1908         {kind: "XV.InvoiceLineTaxBox", attr: "taxes"}
1909       ]}
1910     ],
1911     create: function () {
1912       this.inherited(arguments);
1913       var effectiveKey = this.getEffectiveKey(),
1914         currencyKey = this.getCurrencyKey();
1915
1916       // Set currency and effective attributes on money widgets
1917       this.getComponents().forEach(function (ctl) {
1918         if (ctl.kind === "XV.MoneyWidget") {
1919           ctl.attr.currency = currencyKey;
1920           ctl.attr.effective = effectiveKey;
1921         }
1922       });
1923     }
1924   });
1925   // ..........................................................
1926   // SALES ORDER BASE
1927   //
1928
1929   /**
1930     This is the base kind for Quote and Sales order. This should include all common components
1931     and functions.
1932   */
1933   enyo.kind({
1934     name: "XV.SalesOrderBase",
1935     kind: "XV.Workspace",
1936     printOnSaveSetting: "DefaultPrintSOOnSave",
1937     headerAttrs: ["number", "-", "billtoName"],
1938     published: {
1939       effectiveKey: "orderDate"
1940     },
1941     handlers: {
1942       ontap: "copyBilltoToShipto"
1943     },
1944     create: function () {
1945       this.inherited(arguments);
1946
1947       var effectiveKey = this.getEffectiveKey(),
1948         settings = this.$.settingsGroup.children[0].children,
1949         last = settings[settings.length - 1];
1950
1951       this.getComponents().forEach(function (ctl) {
1952         if (ctl.kind === "XV.MoneyWidget") {
1953           // XXX #refactor -- what does this do?
1954           ctl.getAttr().effective = effectiveKey; // append this property onto the object
1955         }
1956       });
1957
1958       this.$.billtoAddress.$.buttonColumns.createComponent({
1959         kind: "onyx.Button",
1960         classes: "icon-copy",
1961         name: "copyAddressButton",
1962         ontap: "copyBilltoToShipto"
1963       });
1964
1965       // If this is the relationships header, and nothing was added by extensions
1966       // then just hide it.
1967       if (last instanceof onyx.GroupboxHeader) { last.hide(); }
1968     },
1969     customerChanged: function () {
1970       var customer = this.$.customerWidget.getValue(),
1971         id = customer ? customer.get("account") : -1;
1972
1973       this.$.billtoContact.addParameter({attribute: "account", value: id}, true);
1974       this.$.shiptoContact.addParameter({attribute: "account", value: id}, true);
1975       if (customer) {
1976         this.$.customerShiptoWidget.setDisabled(false);
1977         this.$.customerShiptoWidget.addParameter({
1978           attribute: "customer.number",
1979           value: customer.id
1980         });
1981         if (this.$.creditCardWidget) {
1982           this.$.creditCardWidget.addParameter({attribute: "customer", value: customer.id});
1983         }
1984       } else {
1985         this.$.customerShiptoWidget.setDisabled(true);
1986       }
1987     },
1988     attributesChanged: function () {
1989       this.inherited(arguments);
1990       var model = this.getValue(),
1991         customer = model ? model.get("customer") : false,
1992         isFreeFormShipto = customer ? customer.get("isFreeFormShipto") : true,
1993         button = this.$.billtoAddress.$.buttonColumns.$.copyAddressButton;
1994
1995       button.setDisabled(!isFreeFormShipto);
1996       this.customerChanged();
1997     },
1998     controlValueChanged: function (inSender, inEvent) {
1999       this.inherited(arguments);
2000       if (inEvent.originator.name === 'customerWidget') {
2001         this.customerChanged();
2002       }
2003     },
2004     copyBilltoToShipto: function (inSender, inEvent) {
2005       if (inEvent.originator.name === "copyAddressButton") {
2006         this.getValue().copyBilltoToShipto();
2007         return true;
2008       }
2009     }
2010   });
2011
2012   // ..........................................................
2013   // QUOTE
2014   //
2015   enyo.kind({
2016     name: "XV.QuoteWorkspace",
2017     kind: "XV.SalesOrderBase",
2018     title: "_quote".loc(),
2019     model: "XM.Quote",
2020     effectiveKey: "quoteDate",
2021     components: [
2022       {kind: "Panels", arrangerKind: "CarouselArranger",
2023         fit: true, components: [
2024         {kind: "XV.Groupbox", name: "mainPanel", components: [
2025           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2026           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
2027             classes: "in-panel", components: [
2028             {kind: "XV.InputWidget", attr: "number"},
2029             {kind: "XV.DateWidget", name: "dateField", attr: "quoteDate",
2030               label: "_quoteDate".loc()},
2031             {kind: "XV.DateWidget", attr: "scheduleDate"},
2032             {kind: "XV.DateWidget", attr: "expireDate"},
2033             {kind: "XV.InputWidget", attr: "formatStatus",
2034               label: "_status".loc()},
2035             {kind: "onyx.GroupboxHeader", content: "_billTo".loc()},
2036             {kind: "XV.CustomerProspectWidget", attr: "customer",
2037               name: "customerWidget", showAddress: true,
2038               label: "_customer".loc(), nameAttribute: ""
2039             },
2040             {kind: "XV.AddressFieldsWidget",
2041               name: "billtoAddress", attr:
2042               {name: "billtoName", line1: "billtoAddress1",
2043                 line2: "billtoAddress2", line3: "billtoAddress3",
2044                 city: "billtoCity", state: "billtoState",
2045                 postalCode: "billtoPostalCode", country: "billtoCountry"}
2046             },
2047             {kind: "XV.ContactWidget", attr: "billtoContact",
2048               name: "billtoContact"},
2049             {kind: "onyx.GroupboxHeader", content: "_shipTo".loc()},
2050             {kind: "XV.CustomerShiptoWidget", attr: "shipto",
2051               showAddress: true, label: "_number".loc(),
2052               nameAttribute: ""},
2053             {kind: "XV.AddressFieldsWidget",
2054               name: "shiptoAddress", disabled: true,
2055               attr: {name: "shiptoName", line1: "shiptoAddress1",
2056                 line2: "shiptoAddress2", line3: "shiptoAddress3",
2057                 city: "shiptoCity", state: "shiptoState",
2058                 postalCode: "shiptoPostalCode", country: "shiptoCountry"}
2059             },
2060             {kind: "XV.ContactWidget", attr: "shiptoContact",
2061               name: "shiptoContact"},
2062             {kind: "onyx.GroupboxHeader", content: "_orderNotes".loc()},
2063             {kind: "XV.TextArea", attr: "orderNotes", fit: true},
2064             {kind: "onyx.GroupboxHeader", content: "_shippingNotes".loc()},
2065             {kind: "XV.TextArea", attr: "shipNotes", fit: true}
2066           ]}
2067         ]},
2068         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(),
2069           components: [
2070           {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
2071           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
2072             classes: "in-panel", components: [
2073             {kind: "XV.BillingTermsPicker", attr: "terms"},
2074             {kind: "XV.SalesRepPicker", attr: "salesRep"},
2075             {kind: "XV.PercentWidget", attr: "commission"},
2076             {kind: "XV.TaxZonePicker", attr: "taxZone"},
2077             {kind: "XV.SaleTypePicker", attr: "saleType"},
2078             {kind: "onyx.GroupboxHeader", content: "_shipping".loc()},
2079             {kind: "XV.SitePicker", attr: "site"},
2080             {kind: "XV.DateWidget", attr: "packDate"},
2081             {kind: "XV.InputWidget", attr: "fob"},
2082             {kind: "XV.InputWidget", attr: "customerPurchaseOrderNumber",
2083              label: "_custPO".loc()},
2084             {kind: "XV.ShipViaCombobox", attr: "shipVia"},
2085             {kind: "XV.ShipZonePicker", attr: "shipZone"},
2086             {kind: "onyx.GroupboxHeader", content: "_relationships".loc()}
2087           ]}
2088         ]},
2089         {kind: "XV.QuoteCommentBox", attr: "comments"},
2090         {kind: "XV.QuoteDocumentsBox", attr: "documents"}
2091       ]}
2092     ],
2093     create: function () {
2094       this.inherited(arguments);
2095
2096       if (enyo.platform.touch) {
2097         this.$.panels.createComponents([
2098           {kind: "XV.QuoteLineItemBox", attr: "lineItems", title: "_lineItems".loc(),
2099             addBefore: this.$.settingsPanel, classes: "medium-panel"}
2100         ], {owner: this});
2101       } else {
2102         this.$.panels.createComponents([
2103           {kind: "XV.QuoteLineItemGridBox", attr: "lineItems", title: "_lineItems".loc(),
2104             addBefore: this.$.settingsPanel}
2105         ], {owner: this});
2106       }
2107     }
2108   });
2109
2110   XV.registerModelWorkspace("XM.QuoteRelation", "XV.QuoteWorkspace");
2111   XV.registerModelWorkspace("XM.QuoteListItem", "XV.QuoteWorkspace");
2112
2113   // ..........................................................
2114   // LINE ITEM
2115   //
2116   var lineItem = {
2117     kind: "XV.Workspace",
2118     modelAmnesty: true,
2119     handlers: {
2120       onBarcodeCapture: "handleBarcodeCapture"
2121     },
2122     components: [
2123       {kind: "Panels", arrangerKind: "CarouselArranger",
2124         fit: true, components: [
2125         {kind: "XV.Groupbox", name: "mainPanel", components: [
2126           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2127           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2128             classes: "in-panel", fit: true, components: [
2129             {kind: "XV.NumberWidget", attr: "lineNumber"},
2130             {kind: "XV.ItemSiteWidget", attr: {item: "item", site: "site"},
2131               name: "itemSiteWidget",
2132               query: {parameters: [
2133               {attribute: "item.isSold", value: true},
2134               {attribute: "item.isActive", value: true},
2135               {attribute: "isSold", value: true},
2136               {attribute: "isActive", value: true}
2137             ]}},
2138             {kind: "XV.InputWidget", attr: "customerPartNumber"},
2139             {kind: "XV.QuantityWidget", attr: "quantity"},
2140             {kind: "XV.UnitPicker", name: "quantityUnitPicker",
2141               attr: "quantityUnit"},
2142             {kind: "XV.PercentWidget", name: "discount", attr: "discount"},
2143             {kind: "XV.MoneyWidget", attr:
2144               {localValue: "price", currency: ""},
2145               label: "_price".loc(), currencyDisabled: true,
2146               scale: XT.SALES_PRICE_SCALE},
2147             {kind: "XV.UnitPicker", name: "priceUnitPicker",
2148               attr: "priceUnit"},
2149             {kind: "XV.MoneyWidget", attr:
2150               {localValue: "extendedPrice", currency: ""},
2151               label: "_extendedPrice".loc(), currencyDisabled: true,
2152               scale: XT.EXTENDED_PRICE_SCALE},
2153             {kind: "onyx.GroupboxHeader", content: "_delivery".loc()},
2154             {kind: "XV.DateWidget", attr: "scheduleDate"},
2155             {kind: "XV.DateWidget", attr: "promiseDate", showing: false,
2156               name: "promiseDate"},
2157             {kind: "XV.PurchaseOrderLineCharacteristicsWidget",
2158               attr: "characteristics"}
2159           ]}
2160         ]},
2161         {kind: "XV.Groupbox", name: "detailsPanel", title: "_detail".loc(),
2162           components: [
2163           {kind: "onyx.GroupboxHeader", content: "_detail".loc()},
2164           {kind: "XV.ScrollableGroupbox", name: "detailGroup",
2165             classes: "in-panel", fit: true, components: [
2166             {kind: "XV.MoneyWidget", attr: {baseValue: "unitCost"},
2167               label: "_unitCost".loc(), isEditableProperty: "baseValue",
2168               currencyDisabled: true},
2169             {kind: "XV.MoneyWidget", attr: {baseValue: "listPrice"},
2170               label: "_listPrice".loc(), scale: XT.SALES_PRICE_SCALE,
2171               isEditableProperty: "baseValue", currencyDisabled: true},
2172             {kind: "XV.MoneyWidget", attr: {localValue: "customerPrice"},
2173               label: "_customerPrice".loc(), scale: XT.SALES_PRICE_SCALE,
2174               currencyDisabled: true},
2175             {kind: "XV.PercentWidget", attr: "listPriceDiscount"},
2176             {kind: "XV.PercentWidget", attr: "markup"},
2177             {kind: "XV.MoneyWidget", attr: {localValue: "margin"},
2178               label: "_margin".loc(), scale: XT.EXTENDED_PRICE_SCALE,
2179               currencyDisabled: true},
2180             {kind: "onyx.GroupboxHeader", content: "_tax".loc()},
2181             {kind: "XV.TaxTypePicker", attr: "taxType"},
2182             {kind: "XV.MoneyWidget", attr: {localValue: "tax"},
2183               label: "_tax".loc(), currencyDisabled: true},
2184             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
2185             {kind: "XV.TextArea", attr: "notes", fit: true}
2186           ]}
2187         ]}
2188       ]}
2189     ],
2190     create: function () {
2191       this.inherited(arguments);
2192       var effectiveKey = this.getEffectiveKey(),
2193         currencyKey = this.getCurrencyKey(),
2194         comments = this.getCommentBox();
2195
2196       // Show/Hide promise date
2197       this.$.promiseDate.setShowing(XT.session.settings.get("UsePromiseDate"));
2198
2199       // Set currency and effective attributes on money widgets
2200       this.getComponents().forEach(function (ctl) {
2201         if (ctl.kind === "XV.MoneyWidget") {
2202           ctl.attr.currency = currencyKey;
2203           ctl.attr.effective = effectiveKey;
2204         }
2205       });
2206
2207       // Add the Comment Box to Panels
2208       this.$.panels.createComponents([comments], {owner: this});
2209     },
2210     handleBarcodeCapture: function (inSender, inEvent) {
2211       this.$.itemSiteWidget.$.privateItemSiteWidget.$.input.setValue(inEvent.data);
2212       this.$.itemSiteWidget.$.privateItemSiteWidget.autocomplete();
2213     }
2214   };
2215   enyo.mixin(lineItem, XV.LineMixin);
2216
2217   // ..........................................................
2218   // QUOTE LINE ITEM
2219   //
2220   var quoteLineItem = {
2221     name: "XV.QuoteLineWorkspace",
2222     title: "_quoteLine".loc(),
2223     model: "XM.QuoteLine",
2224     published: {
2225       currencyKey: "quote.currency",
2226       effectiveKey: "quote.quoteDate",
2227       commentBox: {kind: "XV.QuoteLineCommentBox", attr: "comments"}
2228     }
2229   };
2230   enyo.mixin(quoteLineItem, XV.QuoteLineMixin);
2231   enyo.mixin(quoteLineItem, lineItem);
2232   enyo.kind(quoteLineItem);
2233
2234   // ..........................................................
2235   // SALES ORDER LINE ITEM
2236   //
2237   var salesOrderLineItem = {
2238     name: "XV.SalesOrderLineWorkspace",
2239     title: "_salesOrderLine".loc(),
2240     model: "XM.SalesOrderLine",
2241     published: {
2242       currencyKey: "salesOrder.currency",
2243       effectiveKey: "salesOrder.orderDate",
2244       commentBox: {kind: "XV.SalesOrderLineCommentBox", attr: "comments"}
2245     }
2246   };
2247   _.extend(salesOrderLineItem, XV.SalesOrderLineMixin, lineItem, {
2248     destroy: function () {
2249       this.bind("off");
2250       this.inherited(arguments);
2251     }
2252   });
2253
2254   enyo.kind(salesOrderLineItem);
2255
2256   // ..........................................................
2257   // SALES ORDER
2258   //
2259
2260   enyo.kind({
2261     name: "XV.SalesOrderWorkspace",
2262     kind: "XV.SalesOrderBase",
2263     title: "_salesOrder".loc(),
2264     handlers: {
2265       onMagstripeCapture: "handleMagstripeCapture",
2266       onPaymentPosted: 'handlePaymentPosted',
2267     },
2268     model: "XM.SalesOrder",
2269     actions: [{
2270       name: "print",
2271       isViewMethod: true,
2272       label: "_print".loc(),
2273       privilege: "MaintainSalesOrders",
2274       prerequisite: "isReadyClean"
2275     }],
2276     components: [
2277       {kind: "Panels", arrangerKind: "CarouselArranger",
2278         fit: true, components: [
2279         {kind: "XV.Groupbox", name: "mainPanel", components: [
2280           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2281           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
2282             classes: "in-panel", components: [
2283             {kind: "XV.InputWidget", attr: "number"},
2284             {kind: "XV.DateWidget", name: "dateField", attr: "orderDate",
2285               label: "_orderDate".loc()},
2286             {kind: "XV.DateWidget", attr: "scheduleDate"},
2287             {kind: "XV.DateWidget", attr: "packDate"},
2288             {kind: "XV.InputWidget", attr: "formatStatus",
2289               label: "_status".loc()},
2290             {kind: "XV.CheckboxWidget", attr: "printOnSave",
2291               label: "_printOnSave".loc()},
2292             {kind: "onyx.GroupboxHeader", content: "_billTo".loc()},
2293             {kind: "XV.SalesCustomerWidget", attr: "customer",
2294                name: "customerWidget", showAddress: true,
2295                label: "_customer".loc(), nameAttribute: ""
2296             },
2297             {kind: "XV.AddressFieldsWidget",
2298               name: "billtoAddress", attr:
2299               {name: "billtoName", line1: "billtoAddress1",
2300                 line2: "billtoAddress2", line3: "billtoAddress3",
2301                 city: "billtoCity", state: "billtoState",
2302                 postalCode: "billtoPostalCode", country: "billtoCountry"}
2303             },
2304             {kind: "XV.ContactWidget", attr: "billtoContact",
2305               name: "billtoContact"},
2306             {kind: "onyx.GroupboxHeader", content: "_shipTo".loc()},
2307             {kind: "XV.CustomerShiptoWidget", attr: "shipto",
2308               showAddress: true, label: "_number".loc(),
2309               nameAttribute: ""},
2310             {kind: "XV.AddressFieldsWidget",
2311               name: "shiptoAddress",
2312               disabled: true,
2313               attr: {name: "shiptoName", line1: "shiptoAddress1",
2314                 line2: "shiptoAddress2", line3: "shiptoAddress3",
2315                 city: "shiptoCity", state: "shiptoState",
2316                 postalCode: "shiptoPostalCode", country: "shiptoCountry"}
2317             },
2318             {kind: "XV.ContactWidget", attr: "shiptoContact",
2319               name: "shiptoContact"},
2320             {kind: "XV.SalesOrderCharacteristicsWidget", attr: "characteristics"},
2321             {kind: "onyx.GroupboxHeader", content: "_orderNotes".loc()},
2322             {kind: "XV.TextArea", attr: "orderNotes", fit: true},
2323             {kind: "onyx.GroupboxHeader", content: "_shippingNotes".loc()},
2324             {kind: "XV.TextArea", attr: "shipNotes", fit: true}
2325           ]}
2326         ]},
2327         {kind: "XV.Groupbox", name: "settingsPanel", title: "_settings".loc(),
2328           components: [
2329           {kind: "onyx.GroupboxHeader", content: "_settings".loc()},
2330           {kind: "XV.ScrollableGroupbox", name: "settingsGroup", fit: true,
2331             classes: "in-panel", components: [
2332             {kind: "XV.BillingTermsPicker", attr: "terms"},
2333             {kind: "XV.SalesRepPicker", attr: "salesRep"},
2334             {kind: "XV.PercentWidget", attr: "commission"},
2335             {kind: "XV.TaxZonePicker", attr: "taxZone"},
2336             {kind: "XV.SaleTypePicker", attr: "saleType"},
2337             {kind: "XV.HoldTypePicker", attr: "holdType"},
2338             {kind: "onyx.GroupboxHeader", content: "_shipping".loc()},
2339             {kind: "XV.CheckboxWidget", attr: "shipComplete"},
2340             {kind: "XV.HeavyweightSitePicker", attr: "site"},
2341             {kind: "XV.InputWidget", attr: "fob"},
2342             {kind: "XV.InputWidget", attr: "customerPurchaseOrderNumber",
2343              label: "_custPO".loc()},
2344             {kind: "XV.ShipViaCombobox", attr: "shipVia"},
2345             {kind: "XV.ShipZonePicker", attr: "shipZone"},
2346             {kind: "XV.ShippingChargePicker", attr: "shipCharge"},
2347             {kind: "onyx.GroupboxHeader", content: "_relationships".loc()}
2348           ]}
2349         ]},
2350         {kind: "XV.SalesOrderCommentBox", name: "salesOrderCommentBox",
2351           attr: "comments"},
2352         {kind: "XV.SalesOrderDocumentsBox", attr: "documents"}
2353       ]}
2354     ],
2355     /**
2356      * @listens onPaymentPosted
2357      */
2358     handlePaymentPosted: function (inSender, inEvent) {
2359       this.requery();
2360     },
2361
2362     valueChanged: function () {
2363       this.inherited(arguments);
2364       if (this.$.salesOrderPaymentBox && this.value) {
2365         this.$.salesOrderPaymentBox.setSalesOrder(this.value);
2366       }
2367     },
2368     create: function () {
2369       this.inherited(arguments);
2370
2371       if (XV.SalesOrderPaymentBox && XT.session.privileges.get('PostCashReceipts')) {
2372         this.$.panels.createComponent({kind: "XV.SalesOrderPaymentBox", title: "_payment".loc(), addBefore: this.$.salesOrderCommentBox},
2373           {owner: this});
2374         if (this.value) {
2375           this.$.salesOrderPaymentBox.setSalesOrder(this.value);
2376         }
2377       }
2378
2379       if (XT.session.privileges.get("ProcessCreditCards") &&
2380           XT.session.settings.get("CCCompany") === "Authorize.Net") {
2381         this.$.panels.createComponent(
2382           {kind: "XV.CreditCardBox", name: "creditCardBox", attr: "customer.creditCards",
2383             addBefore: this.$.salesOrderCommentBox},
2384           {owner: this}
2385         );
2386
2387         // XXX altering this line will break the New button. if I add this to
2388         // paymentPanel, I get 'object has no method getValue' when I click
2389         // 'New' -tjw
2390         this.$.creditCardBox.parent.parent = this;
2391       }
2392
2393       if (enyo.platform.touch) {
2394         this.$.panels.createComponents([
2395           {kind: "XV.SalesOrderLineItemBox", name: "salesOrderLineItemBox",
2396             attr: "lineItems", addBefore: this.$.settingsPanel, classes: "medium-panel"},
2397         ], {owner: this});
2398         this.$.panels.createComponents([
2399           {kind: "XV.SalesOrderWorkflowBox", attr: "workflow", title: "_workflow".loc(),
2400             addBefore: this.$.salesOrderCommentBox, classes: "medium-panel"}
2401         ], {owner: this});
2402       } else {
2403         this.$.panels.createComponents([
2404           {kind: "XV.SalesOrderLineItemGridBox", name: "salesOrderLineItemBox",
2405             attr: "lineItems", addBefore: this.$.settingsPanel},
2406         ], {owner: this});
2407         this.$.panels.createComponents([
2408           {kind: "XV.SalesOrderWorkflowGridBox", attr: "workflow", title: "_workflow".loc(),
2409             addBefore: this.$.salesOrderCommentBox}
2410         ], {owner: this});
2411       }
2412     },
2413     handleHotKey: function (keyCode) {
2414       switch (String.fromCharCode(keyCode)) {
2415       case "L":
2416         if (!this.$.salesOrderLineItemGridBox.disabled) {
2417           this.$.salesOrderLineItemGridBox.newItem();
2418         }
2419         return;
2420       }
2421     },
2422     handleMagstripeCapture: function (inSender, inEvent) {
2423       if (this.$.creditCardBox && !this.$.creditCardBox.$.newButton.disabled) { // XXX sloppy
2424         this.$.salesPanels.setIndex(this.$.salesPanels.getPanels().length);
2425         this.$.creditCardBox.newItemWithData(inEvent.data);
2426       }
2427     },
2428     /**
2429       Reset the grid-box back to its read-only state in the case of "apply"
2430      */
2431     save: function (options) {
2432       this.inherited(arguments);
2433       var gridBox = this.$.salesOrderLineItemGridBox;
2434       // XXX hack to prevent screen from hanging in the case of invalid data
2435       if (gridBox && !XT.app.$.postbooks.$.notifyPopup.getShowing()) {
2436         gridBox.setEditableIndex(null);
2437         gridBox.valueChanged();
2438         gridBox.$.editableGridRow.setShowing(false);
2439       }
2440     }
2441   });
2442
2443   XV.registerModelWorkspace("XM.SalesOrder", "XV.SalesOrderWorkspace");
2444   XV.registerModelWorkspace("XM.SalesOrderWorkflow", "XV.SalesOrderWorkspace");
2445   XV.registerModelWorkspace("XM.SalesOrderRelation", "XV.SalesOrderWorkspace");
2446   XV.registerModelWorkspace("XM.SalesOrderListItem", "XV.SalesOrderWorkspace");
2447
2448   // ..........................................................
2449   // SALES ORDER WORKFLOW
2450   //
2451
2452   enyo.kind({
2453     name: "XV.SalesOrderWorkflowWorkspace",
2454     kind: "XV.ChildWorkspace",
2455     title: "_salesOrderWorkflow".loc(),
2456     model: "XM.SalesOrderWorkflow",
2457     components: [
2458       {kind: "Panels", arrangerKind: "CarouselArranger",
2459         classes: "xv-top-panel", fit: true, components: [
2460         {kind: "XV.Groupbox", name: "mainPanel", components: [
2461           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2462           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
2463             classes: "in-panel", components: [
2464             {kind: "XV.InputWidget", attr: "name"},
2465             {kind: "XV.InputWidget", attr: "description"},
2466             {kind: "XV.SalesOrderWorkflowTypePicker", attr: "workflowType"},
2467             {kind: "XV.WorkflowStatusPicker", attr: "status"},
2468             {kind: "XV.PriorityPicker", attr: "priority", showNone: false},
2469             {kind: "XV.NumberSpinnerWidget", attr: "sequence"},
2470             {kind: "onyx.GroupboxHeader", content: "_schedule".loc()},
2471             {kind: "XV.DateWidget", attr: "dueDate"},
2472             {kind: "XV.DateWidget", attr: "startDate"},
2473             {kind: "XV.DateWidget", attr: "assignDate"},
2474             {kind: "XV.DateWidget", attr: "completeDate"},
2475             {kind: "onyx.GroupboxHeader", content: "_userAccounts".loc()},
2476             {kind: "XV.UserAccountWidget", attr: "owner"},
2477             {kind: "XV.UserAccountWidget", attr: "assignedTo"},
2478             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
2479             {kind: "XV.TextArea", attr: "notes", fit: true}
2480           ]}
2481         ]},
2482         {kind: "XV.Groupbox", name: "onCompletedPanel", title: "_completionActions".loc(),
2483           components: [
2484           {kind: "onyx.GroupboxHeader", content: "_onCompletion".loc()},
2485           {kind: "XV.ScrollableGroupbox", name: "completionGroup", fit: true,
2486             classes: "in-panel", components: [
2487             {kind: "XV.CreditStatusPicker", attr: "completedParentStatus",
2488               noneText: "_noChange".loc(), label: "_nextStatus".loc()},
2489             {kind: "XV.DependenciesWidget",
2490               attr: {workflow: "parent.workflow", successors: "completedSuccessors"}}
2491           ]}
2492         ]},
2493         {kind: "XV.Groupbox", name: "onDeferredPanel", title: "_deferredActions".loc(),
2494           components: [
2495           {kind: "onyx.GroupboxHeader", content: "_onDeferred".loc()},
2496           {kind: "XV.ScrollableGroupbox", name: "deferredGroup", fit: true,
2497             classes: "in-panel", components: [
2498             {kind: "XV.CreditStatusPicker", attr: "deferredParentStatus",
2499               noneText: "_noChange".loc(), label: "_nextStatus".loc()},
2500             {kind: "XV.DependenciesWidget",
2501               attr: {workflow: "parent.workflow", successors: "deferredSuccessors"}}
2502           ]}
2503         ]}
2504       ]}
2505     ]
2506   });
2507   // ..........................................................
2508   // REASON CODE
2509   //
2510
2511   enyo.kind({
2512     name: "XV.ReasonCodeWorkspace",
2513     kind: "XV.Workspace",
2514     title: "_reasonCode".loc(),
2515     model: "XM.ReasonCode",
2516     components: [
2517       {kind: "Panels", arrangerKind: "CarouselArranger",
2518         fit: true, components: [
2519         {kind: "XV.Groupbox", name: "mainPanel", components: [
2520           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2521           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2522             classes: "in-panel", components: [
2523             {kind: "XV.InputWidget", attr: "code"},
2524             {kind: "XV.InputWidget", attr: "description"},
2525             {kind: "XV.ReasonCodeDocumentTypePicker", attr: "documentType"}
2526           ]}
2527         ]}
2528       ]}
2529     ]
2530   });
2531
2532   XV.registerModelWorkspace("XM.ReasonCode", "XV.ReasonCodeWorkspace");
2533
2534   // ..........................................................
2535   // SALES EMAIL PROFILE
2536   //
2537
2538   enyo.kind({
2539     name: "XV.SalesEmailProfileWorkspace",
2540     kind: "XV.EmailProfileWorkspace",
2541     title: "_salesEmailProfile".loc(),
2542     model: "XM.SalesEmailProfile",
2543   });
2544
2545   XV.registerModelWorkspace("XM.SalesEmailProfile", "XV.SalesEmailProfileWorkspace");
2546
2547   // ..........................................................
2548   // SALES REP
2549   //
2550
2551   enyo.kind({
2552     name: "XV.SalesRepWorkspace",
2553     kind: "XV.AccountDocumentWorkspace",
2554     title: "_salesRep".loc(),
2555     model: "XM.SalesRep",
2556     components: [
2557       {kind: "Panels", arrangerKind: "CarouselArranger",
2558         fit: true, components: [
2559         {kind: "XV.Groupbox", name: "mainPanel", components: [
2560           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2561           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2562             classes: "in-panel", components: [
2563             {kind: "XV.InputWidget", attr: "number"},
2564             {kind: "XV.CheckboxWidget", attr: "isActive"},
2565             {kind: "XV.InputWidget", attr: "name"},
2566             {kind: "XV.PercentWidget", attr: "commission"}
2567           ]}
2568         ]}
2569       ]},
2570       {kind: "onyx.Popup", name: "findExistingAccountPopup", centered: true,
2571         modal: true, floating: true, scrim: true, onShow: "popupShown",
2572         onHide: "popupHidden", components: [
2573         {content: "_accountExists".loc()},
2574         {name: "whatToDo", content: "_convertAccountSalesRep".loc()},
2575         {tag: "br"},
2576         {kind: "onyx.Button", name: "convert", content: "_ok".loc(), ontap: "accountConvert",
2577           classes: "onyx-blue xv-popup-button"},
2578         {kind: "onyx.Button", name: "cancel", content: "_cancel".loc(), ontap: "accountCancel",
2579           classes: "xv-popup-button"}
2580       ]}
2581     ]
2582   });
2583
2584   XV.registerModelWorkspace("XM.SalesRep", "XV.SalesRepWorkspace");
2585
2586   // ..........................................................
2587   // SALE TYPE
2588   //
2589
2590   enyo.kind({
2591     name: "XV.SaleTypeWorkspace",
2592     kind: "XV.Workspace",
2593     title: "_saleType".loc(),
2594     model: "XM.SaleType",
2595     components: [
2596       {kind: "Panels", arrangerKind: "CarouselArranger",
2597         fit: true, components: [
2598         {kind: "XV.Groupbox", name: "mainPanel", components: [
2599           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2600           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2601             classes: "in-panel", components: [
2602             {kind: "XV.InputWidget", attr: "code"},
2603             {kind: "XV.InputWidget", attr: "description"},
2604             {kind: "XV.SalesEmailProfilePicker", attr: "emailProfile"},
2605             {kind: "XV.HoldTypePicker", attr: "defaultHoldType"},
2606             {kind: "XV.SaleTypeCharacteristicsWidget", attr: "characteristics"}
2607           ]}
2608         ]},
2609         {kind: "XV.SaleTypeWorkflowBox", attr: "workflow"}
2610       ]}
2611     ]
2612   });
2613
2614   XV.registerModelWorkspace("XM.SaleType", "XV.SaleTypeWorkspace");
2615
2616   // ..........................................................
2617   // SHIFT
2618   //
2619
2620   enyo.kind({
2621     name: "XV.ShiftWorkspace",
2622     kind: "XV.Workspace",
2623     title: "_shift".loc(),
2624     model: "XM.Shift",
2625     components: [
2626       {kind: "Panels", arrangerKind: "CarouselArranger",
2627         fit: true, components: [
2628         {kind: "XV.Groupbox", name: "mainPanel", components: [
2629           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2630           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2631             classes: "in-panel", components: [
2632             {kind: "XV.InputWidget", attr: "number"},
2633             {kind: "XV.InputWidget", attr: "name"}
2634           ]}
2635         ]}
2636       ]}
2637     ]
2638   });
2639
2640   XV.registerModelWorkspace("XM.Shift", "XV.ShiftWorkspace");
2641
2642   // ..........................................................
2643   // SHIP VIA
2644   //
2645
2646   enyo.kind({
2647     name: "XV.ShipViaWorkspace",
2648     kind: "XV.Workspace",
2649     title: "_shipVia".loc(),
2650     model: "XM.ShipVia",
2651     components: [
2652       {kind: "Panels", arrangerKind: "CarouselArranger",
2653         fit: true, components: [
2654         {kind: "XV.Groupbox", name: "mainPanel", components: [
2655           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2656           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2657             classes: "in-panel", components: [
2658             {kind: "XV.InputWidget", attr: "code"},
2659             {kind: "XV.InputWidget", attr: "description"}
2660           ]}
2661         ]}
2662       ]}
2663     ]
2664   });
2665
2666   XV.registerModelWorkspace("XM.ShipVia", "XV.ShipViaWorkspace");
2667
2668   // ..........................................................
2669   // SHIP ZONE
2670   //
2671
2672   enyo.kind({
2673     name: "XV.ShipZoneWorkspace",
2674     kind: "XV.Workspace",
2675     title: "_shipZone".loc(),
2676     model: "XM.ShipZone",
2677     components: [
2678       {kind: "Panels", arrangerKind: "CarouselArranger",
2679         fit: true, components: [
2680         {kind: "XV.Groupbox", name: "mainPanel", components: [
2681           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2682           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2683             classes: "in-panel", components: [
2684             {kind: "XV.InputWidget", attr: "name"},
2685             {kind: "XV.InputWidget", attr: "description"}
2686           ]}
2687         ]}
2688       ]}
2689     ]
2690   });
2691
2692   XV.registerModelWorkspace("XM.ShipZone", "XV.ShipZoneWorkspace");
2693
2694   // ..........................................................
2695   // SITE
2696   //
2697
2698   enyo.kind({
2699     name: "XV.SiteWorkspace",
2700     kind: "XV.Workspace",
2701     title: "_site".loc(),
2702     model: "XM.Site",
2703     components: [
2704       {kind: "Panels", arrangerKind: "CarouselArranger",
2705         fit: true, components: [
2706         {kind: "XV.Groupbox", name: "mainPanel", components: [
2707           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2708           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
2709             classes: "in-panel", components: [
2710             {kind: "XV.InputWidget", attr: "code"},
2711             {kind: "XV.CheckboxWidget", attr: "isActive"},
2712             {kind: "XV.SiteTypePicker", attr: "siteType"},
2713             {kind: "XV.InputWidget", attr: "description"},
2714             {kind: "XV.ContactWidget", attr: "contact"},
2715             {kind: "XV.AddressWidget", attr: "address"},
2716             {kind: "XV.TaxZonePicker", attr: "taxZone"},
2717             {kind: "XV.InputWidget", attr: "incoterms"},
2718             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
2719             {kind: "XV.TextArea", attr: "notes", fit: true}
2720           ]}
2721         ]},
2722         {kind: "XV.SiteCommentBox", attr: "comments"}
2723       ]}
2724     ]
2725   });
2726
2727   XV.registerModelWorkspace("XM.SiteRelation", "XV.SiteWorkspace");
2728   XV.registerModelWorkspace("XM.SiteListItem", "XV.SiteWorkspace");
2729
2730   // ..........................................................
2731   // SITE TYPE
2732   //
2733
2734   enyo.kind({
2735     name: "XV.SiteTypeWorkspace",
2736     kind: "XV.Workspace",
2737     title: "_siteType".loc(),
2738     model: "XM.SiteType"
2739   });
2740
2741   XV.registerModelWorkspace("XM.SiteType", "XV.SiteTypeWorkspace");
2742
2743   // ..........................................................
2744   // STATE
2745   //
2746
2747   enyo.kind({
2748     name: "XV.StateWorkspace",
2749     kind: "XV.Workspace",
2750     title: "_state".loc(),
2751     model: "XM.State",
2752     components: [
2753       {kind: "Panels", arrangerKind: "CarouselArranger",
2754         fit: true, components: [
2755         {kind: "XV.Groupbox", name: "mainPanel", components: [
2756           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2757           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2758             classes: "in-panel", components: [
2759             {kind: "XV.InputWidget", attr: "abbreviation"},
2760             {kind: "XV.InputWidget", attr: "name"},
2761             {kind: "XV.CountryPicker", attr: "country"}
2762           ]}
2763         ]}
2764       ]}
2765     ]
2766   });
2767
2768   XV.registerModelWorkspace("XM.State", "XV.StateWorkspace");
2769
2770   // ..........................................................
2771   // TAX ASSIGNMENT
2772   //
2773
2774   enyo.kind({
2775     name: "XV.TaxAssignmentWorkspace",
2776     kind: "XV.Workspace",
2777     title: "_taxAssignment".loc(),
2778     model: "XM.TaxAssignment",
2779     components: [
2780       {kind: "Panels", arrangerKind: "CarouselArranger",
2781         fit: true, components: [
2782         {kind: "XV.Groupbox", name: "mainPanel", components: [
2783           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2784           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2785             classes: "in-panel", components: [
2786               {kind: "XV.TaxCodePicker", label: "_taxCode".loc(), attr: "tax"},
2787               {kind: "XV.TaxZonePicker", label: "_taxZone".loc(), attr: "taxZone"},
2788               {kind: "XV.TaxTypePicker", label: "_taxType".loc(), attr: "taxType"}
2789             ]}
2790           ]}
2791         ]}
2792       ]
2793     });
2794
2795   XV.registerModelWorkspace("XM.TaxAssignment", "XV.TaxAssignmentWorkspace");
2796
2797   // ..........................................................
2798   // TAX AUTHORITY
2799   //
2800
2801   hash = {
2802     name: "XV.TaxAuthorityWorkspace",
2803     kind: "XV.AccountDocumentWorkspace",
2804     title: "_taxAuthority".loc(),
2805     model: "XM.TaxAuthority",
2806     headerAttrs: ["code", "-", "name"],
2807     handlers: {
2808       onError: "errorNotify"
2809     },
2810     components: [
2811       {kind: "Panels", arrangerKind: "CarouselArranger",
2812         fit: true, components: [
2813         {kind: "XV.Groupbox", name: "mainPanel", components: [
2814           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2815           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
2816             classes: "in-panel", components: [
2817             {kind: "XV.InputWidget", attr: "code"},
2818             {kind: "XV.InputWidget", attr: "name"},
2819             {kind: "XV.InputWidget", attr: "externalReference"},
2820             {kind: "XV.CurrencyPicker", attr: "currency"},
2821             {kind: "XV.InputWidget", attr: "county"},
2822             {kind: "onyx.GroupboxHeader", content: "_address".loc()},
2823             {kind: "XV.AddressWidget", attr: "address"}
2824           ]}
2825         ]}
2826       ]},
2827       {kind: "onyx.Popup", name: "findExistingAccountPopup", centered: true,
2828         modal: true, floating: true, scrim: true, onShow: "popupShown",
2829         onHide: "popupHidden", components: [
2830         {content: "_accountExists".loc()},
2831         {name: "whatToDo", content: "_convertAccountTaxAuthority".loc()},
2832         {tag: "br"},
2833         {kind: "onyx.Button", name: "convert", content: "_ok".loc(), ontap: "accountConvert",
2834           classes: "onyx-blue xv-popup-button"},
2835         {kind: "onyx.Button", name: "cancel", content: "_cancel".loc(), ontap: "accountCancel",
2836           classes: "xv-popup-button"}
2837       ]}
2838     ]
2839   };
2840
2841   hash = enyo.mixin(hash, XV.WorkspaceAddressMixin);
2842   enyo.kind(hash);
2843
2844   XV.registerModelWorkspace("XM.TaxAuthority", "XV.TaxAuthorityWorkspace");
2845   XV.registerModelWorkspace("XM.TaxAuthorityRelation", "XV.TaxAuthorityWorkspace");
2846
2847   // ..........................................................
2848   // TAX CODE
2849   //
2850
2851   enyo.kind({
2852     name: "XV.TaxCodeWorkspace",
2853     kind: "XV.Workspace",
2854     title: "_taxCode".loc(),
2855     model: "XM.TaxCode",
2856     components: [
2857       {kind: "Panels", arrangerKind: "CarouselArranger",
2858         fit: true, components: [
2859         {kind: "XV.Groupbox", name: "mainPanel", components: [
2860           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2861           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2862             classes: "in-panel", components: [
2863             {kind: "XV.InputWidget", attr: "code"},
2864             {kind: "XV.InputWidget", attr: "description"},
2865             {kind: "XV.TaxClassPicker", attr: "class", label: "_taxClass".loc()},
2866             {kind: "XV.TaxAuthorityPicker", attr: "authority", label: "_taxAuthority".loc()},
2867             {kind: "XV.TaxCodePicker", attr: "basis"}
2868           ]}
2869         ]}
2870       ]}
2871     ]
2872   });
2873
2874   XV.registerModelWorkspace("XM.TaxCode", "XV.TaxCodeWorkspace");
2875
2876   // ..........................................................
2877   // TAX CLASS
2878   //
2879
2880   enyo.kind({
2881     name: "XV.TaxClassWorkspace",
2882     kind: "XV.Workspace",
2883     title: "_taxClass".loc(),
2884     model: "XM.TaxClass",
2885     components: [
2886       {kind: "Panels", arrangerKind: "CarouselArranger",
2887         fit: true, components: [
2888         {kind: "XV.Groupbox", name: "mainPanel", components: [
2889           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2890           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2891             classes: "in-panel", components: [
2892             {kind: "XV.InputWidget", attr: "code"},
2893             {kind: "XV.InputWidget", attr: "description"},
2894             {kind: "XV.NumberWidget", attr: "sequence"}
2895           ]}
2896         ]}
2897       ]}
2898     ]
2899   });
2900
2901   XV.registerModelWorkspace("XM.TaxClass", "XV.TaxClassWorkspace");
2902
2903   // ..........................................................
2904   // TAX RATE
2905   //
2906
2907   enyo.kind({
2908     name: "XV.TaxRateWorkspace",
2909     kind: "XV.Workspace",
2910     title: "_taxRate".loc(),
2911     model: "XM.TaxRate",
2912     components: [
2913       {kind: "Panels", arrangerKind: "CarouselArranger",
2914         fit: true, components: [
2915         {kind: "XV.Groupbox", name: "mainPanel", components: [
2916           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2917           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2918             classes: "in-panel", components: [
2919               {kind: "XV.TaxCodePicker", label: "_taxCode".loc(), attr: "tax"},
2920               {kind: "XV.PercentWidget", label: "_percent".loc(), attr: "percent"},
2921               {kind: "XV.MoneyWidget", attr: {localValue: "amount", currency: "currency",
2922                 effective: "effectiveDate"}, label: "_amount".loc()},
2923               {kind: "XV.DateWidget", label: "_effective".loc(), attr: "effectiveDate"},
2924               {kind: "XV.DateWidget", label: "_expires".loc(), attr: "expirationDate"}
2925             ]}
2926           ]}
2927         ]}
2928       ]
2929     });
2930
2931   XV.registerModelWorkspace("XM.TaxRate", "XV.TaxRateWorkspace");
2932
2933   // ..........................................................
2934   // TAX TYPE
2935   //
2936
2937   enyo.kind({
2938     name: "XV.TaxTypeWorkspace",
2939     kind: "XV.Workspace",
2940     title: "_taxType".loc(),
2941     model: "XM.TaxType",
2942     components: [
2943       {kind: "Panels", arrangerKind: "CarouselArranger",
2944         fit: true, components: [
2945         {kind: "XV.Groupbox", name: "mainPanel", components: [
2946           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2947           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2948             classes: "in-panel", components: [
2949             {kind: "XV.InputWidget", attr: "name"},
2950             {kind: "XV.InputWidget", attr: "description"},
2951             {kind: "XV.CheckboxWidget", attr: "isSystem"}
2952           ]}
2953         ]}
2954       ]}
2955     ]
2956   });
2957
2958   XV.registerModelWorkspace("XM.TaxType", "XV.TaxTypeWorkspace");
2959
2960   // ..........................................................
2961   // TAX ZONE
2962   //
2963
2964   enyo.kind({
2965     name: "XV.TaxZoneWorkspace",
2966     kind: "XV.Workspace",
2967     title: "_taxZone".loc(),
2968     model: "XM.TaxZone",
2969     components: [
2970       {kind: "Panels", arrangerKind: "CarouselArranger",
2971         fit: true, components: [
2972         {kind: "XV.Groupbox", name: "mainPanel", components: [
2973           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
2974           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
2975             classes: "in-panel", components: [
2976             {kind: "XV.InputWidget", attr: "code"},
2977             {kind: "XV.InputWidget", attr: "description"}
2978           ]}
2979         ]}
2980       ]}
2981     ]
2982   });
2983
2984   XV.registerModelWorkspace("XM.TaxZone", "XV.TaxZoneWorkspace");
2985
2986   // ..........................................................
2987   // TERMS
2988   //
2989
2990   enyo.kind({
2991     name: "XV.TermsWorkspace",
2992     kind: "XV.Workspace",
2993     title: "_terms".loc(),
2994     model: "XM.Terms",
2995     components: [
2996       {kind: "Panels", arrangerKind: "CarouselArranger",
2997         fit: true, components: [
2998         {kind: "XV.Groupbox", name: "mainPanel", components: [
2999           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3000           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
3001             classes: "in-panel", components: [
3002             {kind: "XV.InputWidget", attr: "code"},
3003             {kind: "XV.InputWidget", attr: "description"},
3004             {kind: "XV.TermsTypePicker", attr: "termsType"},
3005             {kind: "XV.NumberSpinnerWidget", name: "dueDays", attr: "dueDays"},
3006             {kind: "XV.NumberSpinnerWidget", name: "discountDays", attr: "discountDays"},
3007             {kind: "XV.NumberSpinnerWidget", name: "cutOffDay", attr: "cutOffDay"},
3008             {kind: "XV.CheckboxWidget", attr: "isUsedByBilling"},
3009             {kind: "XV.CheckboxWidget", attr: "isUsedByPayments"}
3010           ]}
3011         ]}
3012       ]}
3013     ],
3014     // XXX would be better if we only responded to changes to termstype specifically
3015     attributesChanged: function () {
3016       var termsType = this.getValue().get("termsType");
3017       this.inherited(arguments);
3018
3019       this.$.cutOffDay.setShowing(termsType === XM.Terms.PROXIMO);
3020
3021       if (termsType === XM.Terms.DAYS) {
3022         this.$.dueDays.setLabel("_dueDays".loc());
3023         this.$.discountDays.setLabel("_discountDays".loc());
3024       } else if (termsType === XM.Terms.PROXIMO) {
3025         this.$.dueDays.setLabel("_dueDay".loc());
3026         this.$.discountDays.setLabel("_discountDay".loc());
3027       }
3028     }
3029   });
3030
3031   XV.registerModelWorkspace("XM.Terms", "XV.TermsWorkspace");
3032
3033   // ..........................................................
3034   // TO DO
3035   //
3036
3037   var toDoHash = {
3038     name: "XV.ToDoWorkspace",
3039     kind: "XV.Workspace",
3040     title: "_toDo".loc(),
3041     headerAttrs: ["name"],
3042     model: "XM.ToDo",
3043     components: [
3044       {kind: "Panels", arrangerKind: "CarouselArranger",
3045         fit: true, components: [
3046         {kind: "XV.Groupbox", name: "mainPanel", components: [
3047           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3048           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
3049             classes: "in-panel", components: [
3050             {kind: "XV.CheckboxWidget", attr: "isActive"},
3051             {kind: "XV.InputWidget", attr: "name"},
3052             {kind: "XV.InputWidget", attr: "description"},
3053             {kind: "XV.PriorityPicker", attr: "priority"},
3054             {kind: "XV.ToDoStatusPicker", label: "_status".loc(), attr: "statusProxy"},
3055             {kind: "onyx.GroupboxHeader", content: "_schedule".loc()},
3056             {kind: "XV.DateWidget", attr: "dueDate"},
3057             {kind: "XV.DateWidget", attr: "startDate"},
3058             {kind: "XV.DateWidget", attr: "assignDate"},
3059             {kind: "XV.DateWidget", attr: "completeDate"},
3060             {kind: "onyx.GroupboxHeader", content: "_userAccounts".loc()},
3061             {kind: "XV.UserAccountWidget", attr: "owner"},
3062             {kind: "XV.UserAccountWidget", attr: "assignedTo"},
3063             {kind: "onyx.GroupboxHeader", content: "_notes".loc()},
3064             {kind: "XV.TextArea", attr: "notes", fit: true},
3065             {kind: "onyx.GroupboxHeader", content: "_relationships".loc()},
3066             {kind: "XV.AccountWidget", attr: "account"},
3067             {kind: "XV.ContactWidget", attr: "contact"}
3068           ]}
3069         ]},
3070         {kind: "XV.ToDoCommentBox", attr: "comments"},
3071         {kind: "XV.ToDoDocumentsBox", attr: "documents"}
3072       ]}
3073     ]
3074   };
3075   toDoHash = enyo.mixin(toDoHash, XV.accountNotifyContactMixin);
3076   enyo.kind(toDoHash);
3077   XV.registerModelWorkspace("XM.ToDo", "XV.ToDoWorkspace");
3078   XV.registerModelWorkspace("XM.ToDoRelation", "XV.ToDoWorkspace");
3079   XV.registerModelWorkspace("XM.ToDoListItem", "XV.ToDoWorkspace");
3080
3081   // ..........................................................
3082   // URL
3083   //
3084
3085   enyo.kind({
3086     name: "XV.UrlWorkspace",
3087     kind: "XV.Workspace",
3088     title: "_url".loc(),
3089     model: "XM.Url",
3090     components: [
3091       {kind: "Panels", arrangerKind: "CarouselArranger",
3092         fit: true, components: [
3093         {kind: "XV.Groupbox", name: "mainPanel", components: [
3094           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3095           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
3096             classes: "in-panel", components: [
3097             {kind: "XV.InputWidget", attr: "name"},
3098             {kind: "XV.InputWidget", attr: "path", label: "_address".loc()}
3099           ]}
3100         ]}
3101       ]}
3102     ]
3103   });
3104
3105   XV.registerModelWorkspace("XM.Url", "XV.UrlWorkspace");
3106
3107   // ..........................................................
3108   // UNIT
3109   //
3110
3111   enyo.kind({
3112     name: "XV.UnitWorkspace",
3113     kind: "XV.Workspace",
3114     title: "_unit".loc(),
3115     model: "XM.Unit",
3116     components: [
3117       {kind: "Panels", arrangerKind: "CarouselArranger",
3118         fit: true, components: [
3119         {kind: "XV.Groupbox", name: "mainPanel", components: [
3120           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3121           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
3122             classes: "in-panel", components: [
3123             {kind: "XV.InputWidget", attr: "name"},
3124             {kind: "XV.InputWidget", attr: "description"},
3125             {kind: "XV.CheckboxWidget", attr: "isItemWeight"}
3126           ]}
3127         ]}
3128       ]}
3129     ]
3130   });
3131
3132   XV.registerModelWorkspace("XM.Unit", "XV.UnitWorkspace");
3133
3134   // ..........................................................
3135   // USER ACCOUNT
3136   //
3137
3138   enyo.kind({
3139     name: "XV.UserAccountWorkspace",
3140     kind: "XV.Workspace",
3141     title: "_userAccount".loc(),
3142     model: "XM.UserAccount",
3143     handlers: {
3144       onRefreshPrivileges: "refreshPrivileges"
3145     },
3146     components: [
3147       {kind: "Panels", arrangerKind: "CarouselArranger",
3148         fit: true, components: [
3149         {kind: "XV.Groupbox", name: "mainPanel", components: [
3150           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3151           {kind: "XV.ScrollableGroupbox", name: "mainGroup", fit: true,
3152             classes: "in-panel", components: [
3153             {kind: "XV.InputWidget", attr: "username"},
3154             {kind: "XV.InputWidget", type: "password", attr: "password"},
3155             {kind: "XV.InputWidget", type: "password", name: "passwordCheck",
3156               label: "_reEnterPassword".loc()},
3157             {kind: "XV.LocalePicker", attr: "locale"},
3158             {kind: "XV.CheckboxWidget", attr: "isActive"},
3159             {kind: "XV.InputWidget", attr: "properName"},
3160             {kind: "XV.InputWidget", attr: "initials"},
3161             {kind: "XV.InputWidget", attr: "email"},
3162             {kind: "XV.CheckboxWidget", attr: "useEnhancedAuth"},
3163             {kind: "XV.CheckboxWidget", attr: "disableExport"},
3164             {kind: "XV.CheckboxWidget", attr: "isAgent"},
3165             {kind: "onyx.GroupboxHeader", content: "_extensions".loc()},
3166             {kind: "XV.UserAccountExtensionAssignmentBox", attr: "grantedExtensions",
3167               name: "grantedExtensions" },
3168             {kind: "onyx.GroupboxHeader", content: "_roles".loc()},
3169             {kind: "XV.UserAccountRoleAssignmentBox", attr: "grantedUserAccountRoles",
3170               name: "grantedRoles" },
3171           ]}
3172         ]},
3173         {kind: "XV.Groupbox", name: "privilegePanel", title: "_privileges".loc(),
3174           classes: "xv-assignment-box", components: [
3175           {kind: "onyx.GroupboxHeader", content: "_privileges".loc()},
3176           {kind: "XV.ScrollableGroupbox", fit: true,
3177             classes: "in-panel", components: [
3178             {kind: "XV.UserAccountPrivilegeAssignmentBox", attr: "grantedPrivileges",
3179               name: "grantedPrivileges"}
3180           ]}
3181         ]}
3182       ]}
3183     ],
3184     /*
3185       Ensure that the passwordCheck field is wiped out. This would not happen otherwise
3186       because it's not an attribute of the model.
3187     */
3188     attributesChanged: function (model, options) {
3189       this.inherited(arguments);
3190       if (this.value.getStatus() === XM.Model.READY_CLEAN) {
3191         this.$.passwordCheck.setValue("");
3192       }
3193     },
3194     /**
3195       The passwordCheck field is not on the model. Pipe to a hidden field.
3196      */
3197     controlValueChanged: function (inSender, inEvent) {
3198       if (inEvent.originator.name === 'passwordCheck') {
3199         this.value._passwordCheck = inEvent.originator.value;
3200         return true;
3201       }
3202       this.inherited(arguments);
3203     },
3204
3205     /**
3206       Inject awareness of privileges earned by role into the privilege box when prompted
3207      */
3208     refreshPrivileges: function (inSender, inEvent) {
3209       this.$.grantedPrivileges.mapIds(this.$.grantedRoles.getAssignedCollection().models);
3210       this.$.grantedPrivileges.tryToRender();
3211       this.$.grantedExtensions.mapIds(this.$.grantedRoles.getAssignedCollection().models);
3212       this.$.grantedExtensions.tryToRender();
3213     },
3214
3215     /**
3216       Inject awareness of privileges earned by role into the privilege box
3217         at the start of the model loading
3218      */
3219     statusChanged: function (model, status, options) {
3220       this.inherited(arguments);
3221       if (model.getStatus() & XM.Model.READY) {
3222         this.$.grantedPrivileges.mapIds(this.getValue().get("grantedUserAccountRoles").models);
3223         this.$.grantedPrivileges.tryToRender();
3224         this.$.grantedExtensions.mapIds(this.getValue().get("grantedUserAccountRoles").models);
3225         this.$.grantedExtensions.tryToRender();
3226       }
3227     }
3228   });
3229
3230   XV.registerModelWorkspace("XM.UserAccountRelation", "XV.UserAccountWorkspace");
3231   XV.registerModelWorkspace("XM.UserAccountListItem", "XV.UserAccountWorkspace");
3232
3233   // ..........................................................
3234   // USER ACCOUNT ROLE
3235   //
3236
3237   enyo.kind({
3238     name: "XV.UserAccountRoleWorkspace",
3239     kind: "XV.Workspace",
3240     title: "_userAccountRole".loc(),
3241     model: "XM.UserAccountRole",
3242     components: [
3243       {kind: "Panels", arrangerKind: "CarouselArranger",
3244         fit: true, classes: "xv-top-panel", components: [
3245         {kind: "XV.Groupbox", name: "mainPanel", components: [
3246           {kind: "onyx.GroupboxHeader", content: "_overview".loc()},
3247           {kind: "XV.ScrollableGroupbox", name: "mainGroup",
3248             classes: "in-panel", components: [
3249             {kind: "XV.InputWidget", attr: "name"},
3250             {kind: "XV.InputWidget", attr: "description"},
3251             {kind: "onyx.GroupboxHeader", content: "_extensions".loc()},
3252             {kind: "XV.UserAccountRoleExtensionAssignmentBox", attr: "grantedExtensions",
3253               name: "grantedExtensions" }
3254           ]}
3255         ]},
3256         {kind: "XV.Groupbox", name: "privilegePanel", classes: "xv-assignment-box",
3257             title: "_privileges".loc(), components: [
3258           {kind: "onyx.GroupboxHeader", content: "_privileges".loc()},
3259           {kind: "XV.UserAccountRolePrivilegeAssignmentBox", attr: "grantedPrivileges",
3260             name: "grantedPrivileges" }
3261         ]}
3262       ]}
3263     ]
3264   });
3265
3266   XV.registerModelWorkspace("XM.UserAccountRole", "XV.UserAccountRoleWorkspace");
3267   XV.registerModelWorkspace("XM.UserAccountRoleRelation", "XV.UserAccountRoleWorkspace");
3268   XV.registerModelWorkspace("XM.UserAccountRoleListItem", "XV.UserAccountRoleWorkspace");
3269
3270
3271 }());