Merge pull request #1609 from xtuple/4_5_x
[xtuple] / enyo-client / extensions / source / purchasing / client / widgets / relation.js
1 /*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
2 newcap:true, noarg:true, regexp:true, undef:true, trailing:true,
3 white:true, strict:false*/
4 /*global enyo:true, XT:true, XV:true, Globalize:true, XM:true, _:true */
5
6 (function () {
7
8   XT.extensions.purchasing.initRelationWidgets = function () {
9
10     // ..........................................................
11     // ITEM SOURCE
12     //
13
14     /**
15       This relation widget requires attribute mappings as an object for
16       `itemSource` and `vendorItemNumber`. If a vendor item number is keyed
17       in that is not found, or a null item source is passed in while a vendor
18       item number has a legitimate string, then the vendor item number will
19       be displayed. This allows use of the widget as a basic text field
20       for vendor item number in cases where there is no item source.
21     */
22     enyo.kind({
23       name: "XV.ItemSourceWidget",
24       kind: "XV.RelationWidget",
25       label: "_itemSource".loc(),
26       collection: "XM.ItemSourceCollection",
27       list: "XV.ItemSourceList",
28       keyAttribute: "vendorItemNumber",
29       nameAttribute: "contract.number",
30       published: {
31         showDetail: true,
32         vendorItemNumber: null,
33       },
34       components: [
35         {kind: "FittableColumns", components: [
36           {name: "label", content: "", fit: true, classes: "xv-flexible-label"},
37           {kind: "onyx.InputDecorator", name: "decorator",
38             classes: "xv-input-decorator", components: [
39             {name: "input", kind: "onyx.Input", classes: "xv-subinput",
40               onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
41               onfocus: "receiveFocus"
42             },
43             {kind: "onyx.MenuDecorator", onSelect: "itemSelected", components: [
44               {kind: "onyx.IconButton", classes: "icon-folder-open-alt"},
45               {name: "popupMenu", floating: true, kind: "onyx.Menu",
46                 components: [
47                 {kind: "XV.MenuItem", name: "searchItem", content: "_search".loc()},
48                 {kind: "XV.MenuItem", name: "openItem", content: "_open".loc(),
49                   disabled: true},
50                 {kind: "XV.MenuItem", name: "newItem", content: "_new".loc(),
51                   disabled: true}
52               ]}
53             ]},
54             {name: "completer", kind: "XV.Completer", onSelect: "itemSelected"}
55           ]}
56         ]},
57         {kind: "FittableColumns", name: "detailColumns", components: [
58           {name: "labels", classes: "xv-relationwidget-column left",
59             components: [
60             {name: "contractLabel", content: "_contract".loc() + ":",
61               classes: "xv-relationwidget-description label",
62               showing: false},
63             {name: "minimumQtyLabel", content: "_minimumOrderQuantity".loc() + ":",
64               classes: "xv-relationwidget-description label",
65               showing: false},
66             {name: "multipleQtyLabel", content: "_multipleOrderQuantity".loc() + ":",
67               classes: "xv-relationwidget-description label",
68               showing: false},
69             {name: "earliestDateLabel", content: "_earliestDate".loc() + ":",
70               classes: "xv-relationwidget-description label",
71               showing: false}
72           ]},
73           {name: "data", fit: true, components: [
74             {name: "name", classes: "xv-relationwidget-description hasLabel",
75               showing: false},
76             {name: "description", classes: "xv-relationwidget-description hasLabel",
77               showing: false},
78             {name: "minimumQty", classes: "xv-relationwidget-description hasLabel",
79               showing: false},
80             {name: "multipleQty", classes: "xv-relationwidget-description hasLabel",
81               showing: false},
82             {name: "earliestDate", classes: "xv-relationwidget-description hasLabel",
83               showing: false}
84           ]}
85         ]}
86       ],
87       create: function () {
88         this.inherited(arguments);
89         if (!this.getShowDetail()) {
90           this.$.detailColumns.setStyle("display: none");
91         }
92       },
93       disabledChanged: function () {
94         this.inherited(arguments);
95         var disabled = this.getDisabled();
96         this.$.minimumQty.addRemoveClass("disabled", disabled);
97         this.$.multipleQty.addRemoveClass("disabled", disabled);
98         this.$.earliestDate.addRemoveClass("disabled", disabled);
99       },
100       /**
101         Can accept a two property object with an item source and vendor item number
102         or a full XM.ItemSource object.
103       */
104       setValue: function (obj, options) {
105         options = options || {};
106         var that = this,
107           value = obj instanceof XM.ItemSource || _.isNull(obj) ? obj : obj.itemSource,
108           newId = value ? value.id : null,
109           oldId = this.value ? this.value.id : null,
110           oldVendorItemNumber = this.getVendorItemNumber(),
111           key = this.getFirstKey(),
112           name = this.getNameAttribute(),
113           keyValue = "",
114           nameValue = "",
115           Model = this._collection.model,
116           id,
117           newValue,
118           setPrivileges = function () {
119             if (value && newId) {
120               if (value.couldRead) {
121                 that.$.openItem.setDisabled(!value.couldRead());
122               } else {
123                 that.$.openItem.setDisabled(!value.getClass().canRead());
124               }
125             }
126           };
127
128         if (obj instanceof XM.ItemSource && !_.isNull(obj)) {
129           keyValue = obj.get("vendorItemNumber");
130         } else if (_.isObject(obj)) {
131           keyValue = obj.vendorItemNumber || "";
132         }
133
134         if (_.isString(value)) {
135           if (this.value === value || oldId === value) { return; }
136
137           id = _.isObject(value) ? value.id : value;
138
139           newValue = new Model();
140           options = {
141             id: id,
142             success: function () {
143               that.setValue({
144                 itemSource: newValue,
145                 vendorItemNumber: newValue.get("vendorItemNumber")
146               });
147             },
148             error: function () {
149               XT.log("Error setting relational widget value");
150             }
151           };
152           newValue.fetch(options);
153           return;
154         }
155
156         this.value = value;
157         if (value && value.getValue) {
158           keyValue = value.getValue(key) || "";
159           nameValue = value.getValue(name) || "";
160         }
161         this.setVendorItemNumber(keyValue);
162         this.$.input.setValue(keyValue);
163         this.$.name.setShowing(nameValue);
164         this.$.name.setContent(nameValue);
165
166         // Only notify if selection actually changed
167         if ((newId !== oldId || oldVendorItemNumber !== keyValue) && !options.silent) {
168           this.doValueChange({
169             originator: this,
170             value: {
171               itemSource: value,
172               vendorItemNumber: keyValue
173             }
174           });
175         }
176
177         // Handle menu actions
178         that.$.openItem.setShowing(true);
179         that.$.newItem.setShowing(true);
180         that.$.openItem.setDisabled(true);
181         that.$.newItem.setDisabled(_couldNotCreate.apply(this) || this.disabled);
182         if (Model) { setPrivileges(); }
183
184         if (this.getShowDetail()) {
185           var contract = value ? value.getValue("contract.number") : "",
186             minimumQty = value ? value.get("minimumOrderQuantity") : 0,
187             multipleQty = value ? value.get("multipleOrderQuantity") : 0,
188             earliestDate = value ? XT.date.applyTimezoneOffset(value.get("earliestDate"), true) : null,
189             scale = XT.QTY_SCALE;
190           this.$.contractLabel.setShowing(contract);
191           this.$.minimumQtyLabel.setShowing(minimumQty);
192           this.$.minimumQty.setShowing(minimumQty);
193           this.$.minimumQty.setContent(Globalize.format(minimumQty, "n" + scale));
194           this.$.multipleQtyLabel.setShowing(multipleQty);
195           this.$.multipleQty.setShowing(multipleQty);
196           this.$.multipleQty.setContent(Globalize.format(multipleQty, "n" + scale));
197           this.$.earliestDateLabel.setShowing(earliestDate);
198           this.$.earliestDate.setShowing(earliestDate);
199           this.$.earliestDate.setContent(Globalize.format(earliestDate, "d"));
200         }
201       },
202
203       /** @protected */
204       _fetchSuccess: function () {
205         if (this._relationSelected) { return; }
206         var value = this._collection.length ? this._collection.models[0] : null,
207           vendorItemNumber = value ? value.get("vendorItemSource") : this.$.input.getValue(),
208           target = enyo.dispatcher.captureTarget;
209         this.setValue({
210           itemSource: value,
211           vendorItemNumber: vendorItemNumber
212         });
213         enyo.dispatcher.captureTarget = target;
214       }
215     });
216
217     /** @private */
218     var _couldNotCreate = function () {
219       var Workspace = this._Workspace,
220         Model = this._collection.model,
221         couldNotCreate = true;
222
223       if (Model && Model.couldCreate) {
224         // model is a list item or relation
225         couldNotCreate = !Model.couldCreate();
226       } else if (Model) {
227         // model is a first-class model
228         couldNotCreate = !Model.canCreate();
229       }
230       return couldNotCreate;
231     };
232
233     // ..........................................................
234     // PURCHASE VENDOR
235     //
236
237     enyo.kind({
238       name: "XV.PurchaseVendorWidget",
239       kind: "XV.VendorWidget",
240       collection: "XM.PurchaseVendorRelationCollection"
241     });
242
243     // ..........................................................
244     // VENDOR ADDRESS
245     //
246
247     enyo.kind({
248       name: "XV.VendorAddressWidget",
249       kind: "XV.RelationWidget",
250       collection: "XM.VendorAddressRelationCollection",
251       list: "XV.VendorAddressList",
252       keyAttribute: "code",
253       nameAttribute: ""
254     });
255
256   };
257
258 }());