partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

ProjectReportResultGrid.js (16366B)


      1 Ext.define("PartKeepr.Components.Project.ProjectReportResultGrid", {
      2     extend: "PartKeepr.BaseGrid",
      3 
      4     features: [
      5         {
      6             ftype: 'summary'
      7         }
      8     ],
      9 
     10     viewConfig: {
     11         markDirty: false
     12     },
     13 
     14     initComponent: function ()
     15     {
     16 
     17         this.subGrid = {
     18             xtype: 'gridfoo',
     19             bind: {
     20                 store: '{record.subParts}',
     21                 parentRecord: '{record}'
     22             }
     23         };
     24 
     25         this.columns = [
     26             {
     27                 header: i18n("Qty"), dataIndex: 'quantity',
     28                 width: 100,
     29                 renderers: [{
     30                     rtype: "projectReportQuantity",
     31                     rendererConfig: {
     32                         quantityField: "quantity"
     33                     }
     34                 }]
     35             }, {
     36                 header: i18n("Part Name"),
     37                 renderers: [{
     38                     rtype: "projectReportMetaPart"
     39                 }],
     40                 flex: 2
     41             }, {
     42                 header: i18n("Part Description"),
     43                 dataIndex: "part.description",
     44                 flex: 2
     45             }, {
     46                 header: i18n("Remarks"),
     47                 dataIndex: 'remarks',
     48                 renderers: [{
     49                     rtype: "projectReportRemarks"
     50                 }],
     51                 flex: 1
     52             }, {
     53                 header: i18n("Production Remarks"),
     54                 dataIndex: 'productionRemarks',
     55                 flex: 1
     56             }, {
     57                 header: i18n("Projects"),
     58                 dataIndex: 'projectNames',
     59                 flex: 1
     60             }, {
     61                 header: i18n("Storage Location"), dataIndex: 'part.storageLocation.name',
     62                 width: 100
     63             }, {
     64                 header: i18n("Available"),
     65                 dataIndex: "part.stockLevel",
     66                 renderers: [{
     67                     rtype: "projectReportMetaPartAvailability"
     68                 }],
     69                 width: 75
     70             }, {
     71                 header: i18n("Distributor"),
     72                 dataIndex: 'distributor',
     73                 renderers: [{
     74                     rtype: 'objectField',
     75                     rendererConfig: {
     76                         displayField: 'distributor.name'
     77                     }
     78                 }],
     79                 flex: 1,
     80                 editor: {
     81                     xtype: 'DistributorComboBox',
     82                     returnObject: true,
     83                     triggerAction: 'query',
     84                     ignoreQuery: true,
     85                     forceSelection: true,
     86                     editable: false
     87                 }
     88             }, {
     89                 header: i18n("Distributor Order Number"), dataIndex: 'distributorOrderNumber',
     90                 flex: 1,
     91                 editor: {
     92                     xtype: 'textfield'
     93                 }
     94             }, {
     95                 header: i18n("Item Price"), dataIndex: 'part.averagePrice',
     96                 renderers: [{
     97                     rtype: 'currency'
     98                 }],
     99                 width: 100
    100             }, {
    101                 header: i18n("Sum"),
    102                 dataIndex: 'itemSum',
    103                 renderers: [{
    104                     rtype: 'currency'
    105                 }],
    106                 summaryType: 'sum',
    107                 summaryRenderer: PartKeepr.getApplication().formatCurrency,
    108                 width: 100
    109             }, {
    110                 header: i18n("Order Amount"), dataIndex: 'missing',
    111                 renderers: [{
    112                     rtype: "projectReportQuantity",
    113                     rendererConfig: {
    114                         quantityField: "missing"
    115                     }
    116                 }],
    117                 width: 100
    118             }, {
    119                 header: i18n("Sum (Order)"),
    120                 dataIndex: 'orderSum',
    121                 renderers: [{
    122                     rtype: 'currency'
    123                 }],
    124                 summaryType: 'sum',
    125                 summaryRenderer: PartKeepr.getApplication().formatCurrency,
    126                 width: 100
    127             }
    128         ];
    129 
    130         this.nextMetaPart = Ext.create("Ext.button.Button", {
    131             text: i18n("Next Meta-Part"),
    132             iconCls: 'partkeepr-icon bricks_down',
    133             listeners: {
    134                 click: this.jumpToNextMetaPart,
    135                 scope: this
    136             }
    137         });
    138 
    139         this.previousMetaPart = Ext.create("Ext.button.Button", {
    140             text: i18n("Previous Meta-Part"),
    141             iconCls: 'partkeepr-icon bricks_up',
    142             listeners: {
    143                 click: this.jumpToPreviousMetaPart,
    144                 scope: this
    145             }
    146         });
    147 
    148         this.removeStockButton = Ext.create('Ext.button.Button', {
    149             text: i18n("Remove parts from stock"),
    150             iconCls: 'fugue-icon notification-counter-03',
    151             listeners: {
    152                 click: this.onStockRemovalClick,
    153                 scope: this
    154             }
    155         });
    156 
    157         this.saveReportButton = Ext.create('Ext.button.Button', {
    158             text: i18n("Save Project Report"),
    159             iconCls: 'fugue-icon notification-counter-04',
    160             listeners: {
    161                 click: this.onSaveReportClick,
    162                 scope: this
    163             }
    164         });
    165 
    166         this.autoFillButton = Ext.create('Ext.button.Button', {
    167             text: i18n("Auto-Fill Distributors"),
    168             iconCls: 'fugue-icon notification-counter-02',
    169             listeners: {
    170                 click: this.onAutoFillClick,
    171                 scope: this
    172             }
    173         });
    174 
    175         this.rowExpander = new PartKeepr.Components.ProjectReport.MetaPartRowExpander({
    176             widget: this.subGrid
    177         });
    178 
    179         this.editing = Ext.create('Ext.grid.plugin.CellEditing', {
    180             clicksToEdit: 1,
    181             listeners: {
    182                 beforeedit: this.onBeforeEdit,
    183                 edit: this.onEdit,
    184                 scope: this
    185             }
    186         });
    187 
    188         this.plugins = [
    189             this.rowExpander, this.editing
    190         ];
    191 
    192         this.bbar = [
    193             this.autoFillButton,
    194             this.removeStockButton,
    195             this.saveReportButton,
    196             {xtype: 'tbseparator'},
    197             this.nextMetaPart,
    198             this.previousMetaPart,
    199             {xtype: 'tbseparator'},
    200             Ext.create("PartKeepr.Exporter.GridExporterButton", {
    201                 itemId: 'export',
    202                 genericExporter: false,
    203                 tooltip: i18n("Export"),
    204                 iconCls: "fugue-icon application-export"
    205             }),
    206             Ext.create("PartKeepr.Components.Grid.GridPresetButton", {
    207                 grid: this
    208             })
    209 
    210         ];
    211 
    212         this.callParent(arguments);
    213 
    214     },
    215     /**
    216      * Called when the distributor field is about to be edited.
    217      *
    218      * Filters the distributor list and show only distributors which are assigned to the particular item.
    219      * @param e
    220      * @param context
    221      */
    222     onBeforeEdit: function (e, context)
    223     {
    224         if (context.field !== "distributor")
    225         {
    226             return;
    227         }
    228 
    229         var distributors = context.record.getPart().distributors();
    230 
    231         var filterIds = [];
    232         for (var i = 0; i < distributors.count(); i++)
    233         {
    234             if (distributors.getAt(i).getDistributor().get("enabledForReports") === false)
    235             {
    236                 continue;
    237             }
    238 
    239             if (distributors.getAt(i).get("ignoreForReports"))
    240             {
    241                 continue;
    242             }
    243 
    244             filterIds.push(distributors.getAt(i).getDistributor().getId());
    245         }
    246 
    247         var filter = Ext.create("PartKeepr.util.Filter", {
    248             property: "@id",
    249             operator: 'in',
    250             value: filterIds
    251         });
    252 
    253         context.column.getEditor().store.clearFilter();
    254         context.column.getEditor().store.addFilter(filter);
    255     },
    256     onSaveReportClick: function ()
    257     {
    258         Ext.Msg.prompt(
    259             i18n("Project Report Name"),
    260             i18n("Please enter the project report name:"),
    261             this.doSaveReport,
    262             this,
    263             false,
    264             this.projectReport.get("name")
    265         );
    266     },
    267     doSaveReport: function (button, value)
    268     {
    269         if (button === "ok")
    270         {
    271             this.projectReport.set("name", value);
    272             this.projectReportManager.doSaveProjectReport();
    273         }
    274     },
    275     /**
    276      * Removes all parts in the project view.
    277      */
    278     onStockRemovalClick: function ()
    279     {
    280         if (this.hasMetaParts())
    281         {
    282             Ext.Msg.alert(i18n("Unassigned Meta-Parts"),
    283                 i18n("You have unassigned meta-parts. In order to remove parts from stock, you need to assign the meta-parts first."));
    284             return;
    285         }
    286 
    287         Ext.Msg.confirm(i18n("Remove parts from stock"),
    288             i18n("Do you really want to remove the parts in the project report from the stock?"),
    289             this.removeStocks, this);
    290     },
    291     jumpToPreviousMetaPart: function ()
    292     {
    293         var i;
    294 
    295         for (i = this.getSelectedMetaPartStartIndex() - 1; i >= 0; i--)
    296         {
    297             if (this.selectMetaPart(i))
    298             {
    299                 break;
    300             }
    301         }
    302     },
    303     jumpToNextMetaPart: function ()
    304     {
    305         var i;
    306 
    307         for (i = this.getSelectedMetaPartStartIndex() + 1; i < this.getStore().getCount(); i++)
    308         {
    309             if (this.selectMetaPart(i))
    310             {
    311                 break;
    312             }
    313         }
    314     },
    315     selectMetaPart: function (index)
    316     {
    317         var record = this.getStore().getAt(index);
    318 
    319         if (record.get("metaPart"))
    320         {
    321             this.ensureVisible(record);
    322             this.getSelectionModel().select(record);
    323             return true;
    324         }
    325 
    326         return false;
    327     },
    328     getSelectedMetaPartStartIndex: function ()
    329     {
    330         var selection = this.getSelection();
    331 
    332         if (selection.length === 1)
    333         {
    334             return this.getStore().indexOf(selection[0]);
    335         } else
    336         {
    337             return 0;
    338         }
    339     },
    340 
    341     removeStocks: function (btn)
    342     {
    343         if (btn === "yes")
    344         {
    345 
    346             var store = this.getStore();
    347             var removals = [];
    348 
    349             for (var i = 0; i < store.count(); i++)
    350             {
    351                 var item = store.getAt(i);
    352 
    353                 removals.push({
    354                     part: item.getPart().getId(),
    355                     amount: item.get("quantity"),
    356                     comment: item.getReport().reportProjects().getFieldValues("project.name").join(", "),
    357                     lotNumber: item.projectParts().getFieldValues("lotNumber").join(", "),
    358                     projects: [] // item.getReport().reportProjects()
    359                 });
    360             }
    361 
    362             PartKeepr.PartBundle.Entity.Part.callPostCollectionAction("massRemoveStock",
    363                 {
    364                     "removals": Ext.encode(removals),
    365                     "projects": Ext.encode(this.getProjectsToReport())
    366                 },
    367                 function (options, success)
    368                 {
    369                     if (success)
    370                     {
    371                         Ext.Msg.alert(
    372                             i18n("Stock Removal Complete"),
    373                             i18n("Removed stock and created a new project run.")
    374                         );
    375                     }
    376                 }
    377             );
    378         }
    379     },
    380     onEdit: function (editor, context)
    381     {
    382         if (context.field === "distributor" && context.record.getDistributor() !== null)
    383         {
    384             var partDistributors = context.record.getPart().distributors();
    385 
    386             for (var i = 0; i < partDistributors.count(); i++)
    387             {
    388                 if (partDistributors.getAt(i).getDistributor().getId() === context.record.getDistributor().getId())
    389                 {
    390                     context.record.set("itemPrice", partDistributors.getAt(i).get("price"));
    391                     context.record.set("distributorOrderNumber", partDistributors.getAt(i).get("orderNumber"));
    392                     context.record.set("orderSum", context.record.get("missing") * context.record.get("itemPrice"));
    393                     context.record.set("itemSum", context.record.get("quantity") * context.record.get("itemPrice"));
    394                 }
    395             }
    396         }
    397 
    398     },
    399     onAutoFillClick: function ()
    400     {
    401         var partCount = this.getStore().getCount();
    402         var activeRecord;
    403 
    404         this.projectPartStack = [];
    405 
    406 
    407         for (var i = 0; i < partCount; i++)
    408         {
    409 
    410             activeRecord = this.getStore().getAt(i);
    411 
    412             this.projectPartStack.push(activeRecord);
    413         }
    414 
    415         this.processCheapestDistributorStack(this.projectPartStack.length);
    416 
    417         if (this.waitMessage instanceof Ext.window.MessageBox)
    418         {
    419             this.waitMessage.hide();
    420         }
    421     },
    422     processCheapestDistributorStack: function (totalCount)
    423     {
    424         if (this.projectPartStack.length === 0)
    425         {
    426             if (this.waitMessage instanceof Ext.window.MessageBox)
    427             {
    428                 this.waitMessage.hide();
    429             }
    430             return;
    431         }
    432         this.displayWaitWindow(
    433             i18n("Processing distributors…"),
    434             (totalCount - this.projectPartStack.length) + " / " + totalCount,
    435             1 / totalCount * (totalCount - this.projectPartStack.length));
    436         this.processCheapestDistributorForProjectPart(this.projectPartStack.shift());
    437 
    438         Ext.defer(this.processCheapestDistributorStack, 1, this, [totalCount]);
    439     },
    440     processCheapestDistributorForProjectPart: function (projectPart)
    441     {
    442         var cheapestDistributor = this.getCheapestDistributor(projectPart.getPart());
    443 
    444         if (cheapestDistributor !== null)
    445         {
    446             projectPart.setDistributor(cheapestDistributor.getDistributor());
    447             projectPart.set("distributorOrderNumber", cheapestDistributor.get("orderNumber"));
    448             projectPart.set("itemPrice", cheapestDistributor.get("price"));
    449             projectPart.set("orderSum", projectPart.get("missing") * projectPart.get("itemPrice"));
    450             projectPart.set("itemSum", projectPart.get("quantity") * projectPart.get("itemPrice"));
    451         }
    452     },
    453     getCheapestDistributor: function (part)
    454     {
    455         var cheapestDistributor = null;
    456         var currentPrice;
    457         var activeDistributor;
    458         var lowestPrice;
    459         var firstPositive;
    460 
    461         firstPositive = true;
    462         lowestPrice = 0;
    463 
    464         for (var j = 0; j < part.distributors().count(); j++)
    465         {
    466             activeDistributor = part.distributors().getAt(j);
    467 
    468             if (activeDistributor.getDistributor().get("enabledForReports") === false)
    469             {
    470                 continue;
    471             }
    472 
    473             if (activeDistributor.get("ignoreForReports") === true)
    474             {
    475                 continue;
    476             }
    477 
    478             currentPrice = parseFloat(activeDistributor.get("price"));
    479 
    480             if (currentPrice !== 0)
    481             {
    482                 if (firstPositive)
    483                 {
    484                     lowestPrice = currentPrice;
    485                     cheapestDistributor = activeDistributor;
    486                     firstPositive = false;
    487                 }
    488                 else
    489                 {
    490                     if (currentPrice < lowestPrice)
    491                     {
    492                         lowestPrice = currentPrice;
    493                         cheapestDistributor = activeDistributor;
    494                     }
    495                 }
    496             }
    497         }
    498 
    499         return cheapestDistributor;
    500     },
    501     hasMetaParts: function ()
    502     {
    503         var i, record;
    504         for (i = 0; i < this.getStore().getCount(); i++)
    505         {
    506             record = this.getStore().getAt(i);
    507             if (record.get("metaPart"))
    508             {
    509                 return true;
    510             }
    511         }
    512 
    513         return false;
    514     },
    515     displayWaitWindow: function (text, description, value)
    516     {
    517         this.waitMessage = Ext.MessageBox.show({
    518             msg: text,
    519             title: i18n("Applying distributors…"),
    520             progressText: description,
    521             progress: true,
    522             width: 300
    523         });
    524 
    525         this.waitMessage.updateProgress(value);
    526     },
    527     setProjectsToReport: function (projects)
    528     {
    529         this.reportedProjects = projects;
    530     },
    531     getProjectsToReport: function ()
    532     {
    533         return this.reportedProjects;
    534     }
    535 });