Merge pull request 'Change visible & available methods' (#278) from 2234-getVisibleAvailable into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-by: Joan Sanchez <joan@verdnatura.es>
This commit is contained in:
Joan Sanchez 2020-05-27 05:44:08 +00:00
commit 8b9b65138c
14 changed files with 124 additions and 74 deletions

View File

@ -22,6 +22,7 @@ module.exports = Self => {
Self.getSummary = async id => { Self.getSummary = async id => {
let promises = []; let promises = [];
let summary = {}; let summary = {};
const models = Self.app.models;
// Item basic data and taxes // Item basic data and taxes
let filter = { let filter = {
@ -66,7 +67,7 @@ module.exports = Self => {
} }
] ]
}; };
promises.push(Self.app.models.Item.find(filter)); promises.push(models.Item.find(filter));
// Tags // Tags
filter = { filter = {
@ -78,21 +79,21 @@ module.exports = Self => {
relation: 'tag' relation: 'tag'
} }
}; };
promises.push(Self.app.models.ItemTag.find(filter)); promises.push(models.ItemTag.find(filter));
// Botanical // Botanical
filter = { filter = {
where: {itemFk: id}, where: {itemFk: id},
include: [{relation: 'genus'}, {relation: 'specie'}] include: [{relation: 'genus'}, {relation: 'specie'}]
}; };
promises.push(Self.app.models.ItemBotanical.find(filter)); promises.push(models.ItemBotanical.find(filter));
// Niches // Niches
filter = { filter = {
where: {itemFk: id}, where: {itemFk: id},
include: {relation: 'warehouse'} include: {relation: 'warehouse'}
}; };
promises.push(Self.app.models.ItemNiche.find(filter)); promises.push(models.ItemNiche.find(filter));
let res = await Promise.all(promises); let res = await Promise.all(promises);
@ -101,15 +102,10 @@ module.exports = Self => {
[summary.botanical] = res[2]; [summary.botanical] = res[2];
summary.niches = res[3]; summary.niches = res[3];
// Visible Avaible res = await models.Item.getVisibleAvailable(summary.item.id, summary.item.itemType().warehouseFk);
let query = `
CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`;
let options = [summary.item.id, summary.item.itemType().warehouseFk, false]; summary.available = res.available;
[res] = await Self.rawSql(query, options); summary.visible = res.visible;
summary.available = res[0].available ? res[0].available : '-';
summary.visible = res[0].visible ? res[0].visible : '-';
return summary; return summary;
}; };
}; };

View File

@ -1,3 +1,4 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('getVisibleAvailable', { Self.remoteMethod('getVisibleAvailable', {
description: 'Returns visible and available for params', description: 'Returns visible and available for params',
@ -11,6 +12,11 @@ module.exports = Self => {
arg: 'warehouseFk', arg: 'warehouseFk',
type: 'Number', type: 'Number',
required: true, required: true,
},
{
arg: 'dated',
type: 'Date',
required: false,
}], }],
returns: { returns: {
type: ['object'], type: ['object'],
@ -22,15 +28,35 @@ module.exports = Self => {
} }
}); });
Self.getVisibleAvailable = async(id, warehouseFk) => { Self.getVisibleAvailable = async(id, warehouseFk, dated = new Date()) => {
let query = ` let stmts = [];
CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`;
let options = [id, warehouseFk, false]; stmts.push(new ParameterizedSQL(
[res] = await Self.rawSql(query, options); 'CALL cache.available_refresh(@availableCalc, FALSE, ?, ?)', [
warehouseFk,
dated
]
));
stmts.push(new ParameterizedSQL(
'CALL cache.visible_refresh(@visibleCalc, FALSE,?)', [
warehouseFk
]
));
const visibleIndex = stmts.push(new ParameterizedSQL(
'SELECT visible FROM cache.visible WHERE calc_id = @visibleCalc AND item_id = ?', [
id
]
)) - 1;
const availableIndex = stmts.push(new ParameterizedSQL(
'SELECT available FROM cache.available WHERE calc_id = @availableCalc AND item_id = ?', [
id
]
)) - 1;
const sql = ParameterizedSQL.join(stmts, ';');
let res = await Self.rawStmt(sql);
return { return {
available: res[0].available, available: res[availableIndex][0] ? res[availableIndex][0].available : 0,
visible: res[0].visible}; visible: res[visibleIndex][0] ? res[visibleIndex][0].visible : 0};
}; };
}; };

View File

@ -61,13 +61,9 @@ module.exports = Self => {
}, options); }, options);
} }
let query = ` res = await models.Item.getVisibleAvailable(itemFk, warehouseFk);
CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`;
let params = [itemFk, warehouseFk, true]; let newQuantity = res.visible - quantity;
let [res] = await Self.rawSql(query, params, options);
let newQuantity = res[0].visible - quantity;
await models.Sale.create({ await models.Sale.create({
ticketFk: ticketFk, ticketFk: ticketFk,

View File

@ -0,0 +1,33 @@
const app = require('vn-loopback/server/server');
describe('item getVisibleAvailable()', () => {
it('should check available visible for today', async() => {
const itemFk = 1;
const warehouseFk = 1;
const dated = new Date();
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated);
expect(result.available).toEqual(187);
expect(result.visible).toEqual(92);
});
it('should check available visible for no dated', async() => {
const itemFk = 1;
const warehouseFk = 1;
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk);
expect(result.available).toEqual(187);
expect(result.visible).toEqual(92);
});
it('should check available visible for yesterday', async() => {
const itemFk = 1;
const warehouseFk = 1;
let dated = new Date();
dated.setDate(dated.getDate() - 1);
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated);
expect(result.available).toEqual(0);
expect(result.visible).toEqual(92);
});
});

View File

@ -14,13 +14,8 @@ describe('regularize()', () => {
it('should create a new ticket and add a line', async() => { it('should create a new ticket and add a line', async() => {
let ctx = {req: {accessToken: {userId: 18}}}; let ctx = {req: {accessToken: {userId: 18}}};
let res = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk);
let query = `CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; let visible = res.visible;
let options = [itemFk, warehouseFk, true];
let [res] = await app.models.Item.rawSql(query, options);
let visible = res[0].visible;
let saleQuantity = visible - 11; let saleQuantity = visible - 11;
let ticketFk = await app.models.Item.regularize(ctx, itemFk, 11, warehouseFk); let ticketFk = await app.models.Item.regularize(ctx, itemFk, 11, warehouseFk);

View File

@ -1,5 +1,5 @@
<slot-descriptor> <slot-descriptor>
<vn-item-descriptor warehouse-fk="$ctrl.warehouseFk"> <vn-item-descriptor warehouse-fk="$ctrl.warehouseFk" dated="$ctrl.dated">
<btn-three> <btn-three>
<vn-quick-link <vn-quick-link
tooltip="Item diary" tooltip="Item diary"

View File

@ -2,14 +2,16 @@ import ngModule from '../module';
import DescriptorPopover from 'salix/components/descriptor-popover'; import DescriptorPopover from 'salix/components/descriptor-popover';
class Controller extends DescriptorPopover { class Controller extends DescriptorPopover {
show(parent, id, lineFk) { show(parent, id, lineFk, dated) {
super.show(parent, id); super.show(parent, id);
this.lineFk = lineFk; this.lineFk = lineFk;
this.dated = dated;
} }
hide() { hide() {
super.hide(); super.hide();
this.lineFk = null; this.lineFk = null;
this.dated = null;
} }
} }
@ -18,6 +20,7 @@ ngModule.vnComponent('vnItemDescriptorPopover', {
controller: Controller, controller: Controller,
bindings: { bindings: {
warehouseFk: '<?', warehouseFk: '<?',
lineFk: '<?' lineFk: '<?',
dated: '<?'
} }
}); });

View File

@ -31,7 +31,8 @@ class Controller extends Descriptor {
if (!this.item) return; if (!this.item) return;
const params = { const params = {
warehouseFk: this.item.itemType.warehouseFk warehouseFk: this.item.itemType.warehouseFk,
dated: this.dated
}; };
return this.$http.get(`Items/${this.id}/getVisibleAvailable`, {params}) return this.$http.get(`Items/${this.id}/getVisibleAvailable`, {params})
@ -65,6 +66,7 @@ ngModule.vnComponent('vnItemDescriptor', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,
bindings: { bindings: {
item: '<' item: '<',
dated: '<'
} }
}); });

View File

@ -33,4 +33,14 @@ describe('vnItemDescriptor', () => {
expect(controller.item).toEqual(item); expect(controller.item).toEqual(item);
}); });
}); });
describe('updateStock()', () => {
it(`should perform a get query to store the item data into the controller`, () => {
$httpBackend.expectGET(`Items/${item.id}/getCard`).respond(item);
controller.id = item.id;
$httpBackend.flush();
expect(controller.item).toEqual(item);
});
});
}); });

View File

@ -47,14 +47,9 @@ module.exports = Self => {
include: {relation: 'ticket'} include: {relation: 'ticket'}
}, options); }, options);
let [[stock]] = await Self.rawSql(`CALL vn.item_getVisibleAvailable(?,?,?,?)`, [ const res = await models.Item.getVisibleAvailable(ctx.args.itemFk, request.ticket().warehouseFk, request.ticket().shipped);
ctx.args.itemFk,
request.ticket().shipped,
request.ticket().warehouseFk,
false
], options);
if (stock.available < 0) if (res.available < 0)
throw new UserError(`This item is not available`); throw new UserError(`This item is not available`);
if (request.saleFk) { if (request.saleFk) {

View File

@ -42,15 +42,9 @@ module.exports = Self => {
const item = await models.Item.findById(itemId); const item = await models.Item.findById(itemId);
const ticket = await models.Ticket.findById(id); const ticket = await models.Ticket.findById(id);
const shouldRefresh = false; const res = await models.Item.getVisibleAvailable(itemId, ticket.warehouseFk, ticket.shipped);
const [[stock]] = await Self.rawSql(`CALL vn.item_getVisibleAvailable(?, ?, ?, ?)`, [
itemId,
ticket.shipped,
ticket.warehouseFk,
shouldRefresh
]);
if (stock.available < quantity) if (res.available < quantity)
throw new UserError(`This item is not available`); throw new UserError(`This item is not available`);
const newSale = await models.Sale.create({ const newSale = await models.Sale.create({

View File

@ -121,7 +121,7 @@
</vn-td> </vn-td>
<vn-td number shrink> <vn-td number shrink>
<span <span
ng-click="descriptor.show($event, sale.itemFk, sale.id)" ng-click="descriptor.show($event, sale.itemFk, sale.id, $ctrl.ticket.shipped)"
class="link"> class="link">
{{sale.itemFk | zeroFill:6}} {{sale.itemFk | zeroFill:6}}
</span> </span>

View File

@ -61,8 +61,8 @@ describe('Zone Component vnZoneDeliveryDays', () => {
expect(controller.$.data).toEqual(expectedData); expect(controller.$.data).toEqual(expectedData);
}); });
}); });
// Petición #2259 cread
xdescribe('onSelection()', () => { describe('onSelection()', () => {
it('should not call the show popover method if events array is empty', () => { it('should not call the show popover method if events array is empty', () => {
jest.spyOn(controller.$.zoneEvents, 'show'); jest.spyOn(controller.$.zoneEvents, 'show');

38
package-lock.json generated
View File

@ -3244,7 +3244,7 @@
}, },
"util": { "util": {
"version": "0.10.3", "version": "0.10.3",
"resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4060,7 +4060,7 @@
"base": { "base": {
"version": "0.11.2", "version": "0.11.2",
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=",
"dev": true, "dev": true,
"requires": { "requires": {
"cache-base": "^1.0.1", "cache-base": "^1.0.1",
@ -4577,7 +4577,7 @@
"cache-base": { "cache-base": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=",
"dev": true, "dev": true,
"requires": { "requires": {
"collection-visit": "^1.0.0", "collection-visit": "^1.0.0",
@ -4754,7 +4754,7 @@
"class-utils": { "class-utils": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
"integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=",
"dev": true, "dev": true,
"requires": { "requires": {
"arr-union": "^3.1.0", "arr-union": "^3.1.0",
@ -5816,7 +5816,7 @@
"dot-prop": { "dot-prop": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
"integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=",
"requires": { "requires": {
"is-obj": "^1.0.0" "is-obj": "^1.0.0"
} }
@ -6751,7 +6751,7 @@
}, },
"file-loader": { "file-loader": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
"integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -7918,7 +7918,7 @@
"global-modules": { "global-modules": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
"dev": true, "dev": true,
"requires": { "requires": {
"global-prefix": "^1.0.1", "global-prefix": "^1.0.1",
@ -8500,7 +8500,7 @@
"dependencies": { "dependencies": {
"es6-promise": { "es6-promise": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
"integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=",
"dev": true "dev": true
}, },
@ -9579,7 +9579,7 @@
"is-plain-object": { "is-plain-object": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=",
"dev": true, "dev": true,
"requires": { "requires": {
"isobject": "^3.0.1" "isobject": "^3.0.1"
@ -9935,7 +9935,7 @@
"jasmine-spec-reporter": { "jasmine-spec-reporter": {
"version": "4.2.1", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz",
"integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", "integrity": "sha1-HWMq7ANBZwrTJPkrqEtLMrNeniI=",
"dev": true, "dev": true,
"requires": { "requires": {
"colors": "1.1.2" "colors": "1.1.2"
@ -11932,7 +11932,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}, },
"mississippi": { "mississippi": {
@ -12972,7 +12972,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "0.0.10", "version": "0.0.10",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true "dev": true
}, },
@ -14180,7 +14180,7 @@
"dependencies": { "dependencies": {
"jsesc": { "jsesc": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"dev": true "dev": true
} }
@ -14558,7 +14558,7 @@
}, },
"safe-regex": { "safe-regex": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -14648,7 +14648,7 @@
"dependencies": { "dependencies": {
"source-map": { "source-map": {
"version": "0.4.4", "version": "0.4.4",
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -15006,7 +15006,7 @@
"snapdragon-node": { "snapdragon-node": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=",
"dev": true, "dev": true,
"requires": { "requires": {
"define-property": "^1.0.0", "define-property": "^1.0.0",
@ -15057,7 +15057,7 @@
"snapdragon-util": { "snapdragon-util": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=",
"dev": true, "dev": true,
"requires": { "requires": {
"kind-of": "^3.2.0" "kind-of": "^3.2.0"
@ -15332,7 +15332,7 @@
"split-string": { "split-string": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
"integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=",
"dev": true, "dev": true,
"requires": { "requires": {
"extend-shallow": "^3.0.0" "extend-shallow": "^3.0.0"
@ -16409,7 +16409,7 @@
"touch": { "touch": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=",
"dev": true, "dev": true,
"requires": { "requires": {
"nopt": "~1.0.10" "nopt": "~1.0.10"