Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2341-Entry_lastBuy_section

This commit is contained in:
Carlos Jimenez Ruiz 2020-09-01 17:45:00 +02:00
commit 9fa3f17a9a
44 changed files with 685 additions and 254 deletions

View File

@ -2,6 +2,9 @@
"Account": {
"dataSource": "vn"
},
"AccountingType": {
"dataSource": "vn"
},
"Bank": {
"dataSource": "vn"
},

View File

@ -0,0 +1,30 @@
{
"name": "AccountingType",
"base": "VnModel",
"options": {
"mysql": {
"table": "accountingType"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"description": {
"type": "String",
"required": true
},
"receiptDescription": {
"type": "String",
"required": true
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -2,39 +2,49 @@
"name": "Bank",
"base": "VnModel",
"options": {
"mysql": {
"table": "bank"
}
"mysql": {
"table": "bank"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"bank": {
"type": "string",
"required": true
},
"account": {
"type": "string",
"required": true
},
"cash": {
"type": "string",
"required": true
},
"entityFk": {
"type": "string",
"required": true
},
"isActive": {
"type": "string",
"required": true
},
"currencyFk": {
"type": "string",
"required": true
}
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"bank": {
"type": "String",
"required": true
},
"account": {
"type": "String",
"required": true
},
"accountingTypeFk": {
"type": "Number",
"required": true,
"mysql": {
"columnName": "cash"
}
},
"entityFk": {
"type": "Number",
"required": true
},
"isActive": {
"type": "Boolean",
"required": true
},
"currencyFk": {
"type": "Number",
"required": true
}
},
"relations": {
"accountingType": {
"type": "belongsTo",
"model": "AccountingType",
"foreignKey": "accountingTypeFk"
}
}
}
}

View File

@ -0,0 +1,44 @@
USE `vn`;
DROP procedure IF EXISTS `vn`.`itemLastEntries`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `itemLastEntries__`(IN `vItem` INT, IN `vDays` DATE)
BEGIN
SELECT
w.id AS warehouseFk,
w.name AS warehouse,
tr.landed,
b.entryFk,
b.isIgnored,
b.price2,
b.price3,
b.stickers,
b.packing,
b.`grouping`,
b.groupingMode,
b.weight,
i.stems,
b.quantity,
b.buyingValue,
b.packageFk ,
s.id AS supplierFk,
s.name AS supplier
FROM itemType it
RIGHT JOIN (entry e
LEFT JOIN supplier s ON s.id = e.supplierFk
RIGHT JOIN buy b ON b.entryFk = e.id
LEFT JOIN item i ON i.id = b.itemFk
LEFT JOIN ink ON ink.id = i.inkFk
LEFT JOIN travel tr ON tr.id = e.travelFk
LEFT JOIN warehouse w ON w.id = tr.warehouseInFk
LEFT JOIN origin o ON o.id = i.originFk
) ON it.id = i.typeFk
LEFT JOIN edi.ekt ek ON b.ektFk = ek.id
WHERE b.itemFk = vItem And tr.shipped BETWEEN vDays AND DATE_ADD(CURDATE(), INTERVAl + 10 DAY)
ORDER BY tr.landed DESC , b.id DESC;
END$$
DELIMITER ;
;

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`accountingType`
ADD COLUMN `receiptDescription` VARCHAR(50) NULL AFTER `description`;

View File

@ -116,13 +116,13 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
('GVC', '1', '0', '1', '0', '106'),
('HEJ', '2', '0', '1', '0', '106');
INSERT INTO `vn`.`accountingType`(`id`, `description`)
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`)
VALUES
(1, 'Digital money'),
(2, 'Cash'),
(3, 'Card'),
(4, 'Stolen Money'),
(5, 'Miscellaneous');
(1, 'Digital money', ''),
(2, 'Cash', 'Cash'),
(3, 'Card', 'Pay on receipt'),
(4, 'Stolen Money', ''),
(5, 'Miscellaneous', '');
INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
VALUES
@ -133,8 +133,8 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
VALUES
(1, 'Pay on receipt', '0000000000', 4, 0, 1, 1),
(2, 'Cash', '1111111111', 1, 0, 1, 1);
(1, 'Pay on receipt', '0000000000', 3, 0, 1, 1),
(2, 'Cash', '1111111111', 2, 0, 1, 1);
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
VALUES
@ -766,6 +766,26 @@ INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `create
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18),
(10, 7, 7, 71, CURDATE(), 1, 1, 1, 18);
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `isOnOffer`, `expenceFk`, `isBargain`, `comment`, `relevancy`, `image`, `taxClassFk`, `subName`)
VALUES
(1, 2, 70, 'AMA', 1, 1, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, 67, 1, NULL),
(2, 2, 70, 'AZL', 1, 2, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, 66, 1, NULL),
(3, 1, 60, 'AMR', 1, 3, NULL, 1, 05080000, 0, 4751000000, 0, NULL, 0, 65, 1, NULL),
(4, 1, 60, 'AMR', 1, 1, NULL, 1, 05080000, 1, 4751000000, 0, NULL, 0, 69, 2, NULL),
(5, 3, 30, 'GRE', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, 74, 2, NULL),
(6, 5, 30, 'GRE', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 62, 2, NULL),
(7, 5, 90, 'AZL', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 64, 2, NULL),
(8, 2, 70, 'AMA', 1, 1, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, 75, 1, NULL),
(9, 2, 70, 'AZL', 1, 2, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, 76, 1, NULL),
(10, 1, 60, 'AMR', 1, 3, NULL, 1, 05080000, 0, 4751000000, 0, NULL, 0, 77, 1, NULL),
(11, 1, 60, 'AMR', 1, 1, NULL, 1, 05080000, 1, 4751000000, 0, NULL, 0, 78, 2, NULL),
(12, 3, 30, 'GRE', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, 82, 2, NULL),
(13, 5, 30, 'GRE', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 83, 2, NULL),
(14, 5, 90, 'AZL', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 84, 2, NULL),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, NULL),
(16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, NULL),
(71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 1, 4751000000, 0, NULL, 0, 88, 2, NULL);
INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPackageReturnable`, `created`, `itemFk`, `price`)
VALUES
(1, 0.00, 10, 10, 0, 1, CURDATE(), 6, 1.50),
@ -777,6 +797,19 @@ INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPack
('cc', 1640038.00, 56.00, 220.00, 128.00, 1, CURDATE(), 15, 90.00),
('pallet 100', 2745600.00, 100.00, 220.00, 120.00, 1, CURDATE(), 16, 0.00);
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `workerFk`, `packagingFk`)
VALUES
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 1),
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 1),
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 3, 1, 1),
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 1),
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 1),
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 1, 1, 1),
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), 1, 1, 1, 1),
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), 1, 1, 1, 1),
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 1),
(10, 7, 7, 71, CURDATE(), 1, 1, 1, 1);
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
VALUES
(1, 1, 2, 2, CURDATE(), NULL),

View File

@ -189,8 +189,9 @@ export default {
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]',
saveButton: '.vn-dialog.shown [response="accept"]',
firstBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)'
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield'
},
webPayment: {
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',

View File

@ -53,15 +53,28 @@ describe('Client balance path', () => {
expect(message.type).toBe('success');
});
it('should check balance is now 0 and the company is now VNL becouse the user local settings were removed', async() => {
it('should edit the 1st line reference', async() => {
await page.waitToClick(selectors.clientBalance.firstLineReference);
await page.write(selectors.clientBalance.firstLineReferenceInput, 'Miscellaneous payment');
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
expect(message.type).toBe('success');
});
it('should check balance is now 0, the reference was saved and the company is now VNL becouse the user local settings were removed', async() => {
await page.waitForSpinnerLoad();
let company = await page
.waitToGetProperty(selectors.clientBalance.company, 'value');
let reference = await page
.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
let firstBalanceLine = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText');
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(company).toEqual('VNL');
expect(reference).toEqual('Miscellaneous payment');
expect(firstBalanceLine).toContain('0.00');
});
@ -76,7 +89,7 @@ describe('Client balance path', () => {
it('should check balance is now -100', async() => {
let result = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText');
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(result).toContain('-€100.00');
});
@ -92,7 +105,7 @@ describe('Client balance path', () => {
it('should check balance is now 50', async() => {
let result = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText');
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(result).toEqual('€50.00');
});

View File

@ -31,7 +31,7 @@ describe('Item request path', () => {
it('should the status of the request should now be accepted', async() => {
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
expect(status).toContain('Aceptada');
expect(status).toContain('Accepted');
});
it('should now click on the second declain request icon then type the reason', async() => {
@ -40,6 +40,6 @@ describe('Item request path', () => {
await page.respondToDialog('accept');
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
expect(status).toContain('Denegada');
expect(status).toContain('Denied');
});
});

View File

@ -67,13 +67,13 @@ export default class Contextmenu {
get cell() {
if (!this.target) return null;
return this.target.closest('vn-td, .vn-td');
return this.target.closest('vn-td, .vn-td, vn-td-editable');
}
get cellIndex() {
if (!this.row) return null;
const cells = this.row.querySelectorAll('vn-td, .vn-td');
const cells = this.row.querySelectorAll('vn-td, .vn-td, vn-td-editable');
return Array.from(cells).findIndex(
cellItem => cellItem == this.cell
);

View File

@ -403,8 +403,8 @@ module.exports = {
back,
backOnly,
backWatch,
backTestOnce,
backTest,
backTestOnce,
e2e,
i,
install,

View File

@ -42,11 +42,11 @@ module.exports = Self => {
r.workerFk,
c.code company,
r.created,
r.invoiceFk ref,
r.invoiceFk description,
NULL debit,
r.amountPaid credit,
r.bankFk,
u.nickname userNickname,
u.name userName,
r.clientFk,
FALSE hasPdf,
FALSE isInvoice

View File

@ -17,11 +17,17 @@
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
url="Banks"
label="Bank"
url="Banks"
show-field="bank"
value-field="id"
ng-model="$ctrl.receipt.bankFk">
fields="['accountingTypeFk']"
include="{relation: 'accountingType'}"
order="id"
ng-model="$ctrl.receipt.bankFk"
search-function="{or: [{id: $search}, {bank: {like: '%'+ $search +'%'}}]}"
selection="$ctrl.bankSelection">
<tpl-item>{{id}}: {{bank}}</tpl-item>
</vn-autocomplete>
<vn-input-number
vn-focus
@ -31,6 +37,13 @@
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
label="Reference"
ng-model="$ctrl.receipt.description"
rule>
</vn-textfield>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>

View File

@ -50,6 +50,19 @@ class Controller extends Dialog {
return this.receipt.description;
}
get bankSelection() {
return this._bankSelection;
}
set bankSelection(value) {
this._bankSelection = value;
if (value) {
const accountingType = value.accountingType;
this.receipt.description = accountingType && accountingType.receiptDescription;
}
}
getAmountPaid() {
const filter = {
where: {

View File

@ -0,0 +1,76 @@
import './index';
describe('Client', () => {
describe('Component vnClientBalancCreate', () => {
let controller;
let $httpBackend;
let $httpParamSerializer;
beforeEach(ngModule('client'));
beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
let $scope = $rootScope.$new();
const $element = angular.element('<vn-client-balance-create></vn-client-balance-create>');
const $transclude = {
$$boundTransclude: {
$$slots: []
}
};
controller = $componentController('vnClientBalanceCreate', {$element, $scope, $transclude});
controller.receipt = {
clientFk: 101,
companyFk: 442
};
}));
describe('bankSelection() setter', () => {
it('should set the receipt description property', () => {
controller.bankSelection = {
id: 1,
bank: 'Cash',
accountingType: {
id: 2,
receiptDescription: 'Cash'
}
};
expect(controller.receipt.description).toEqual('Cash');
});
});
describe('getAmountPaid()', () => {
it('should make an http GET query and then set the receipt amountPaid property', () => {
controller.$params = {id: 101};
const receipt = controller.receipt;
const filter = {
where: {
clientFk: 101,
companyFk: 442
}
};
const serializedParams = $httpParamSerializer({filter});
$httpBackend.expect('GET', `ClientRisks?${serializedParams}`,).respond([{amount: 20}]);
controller.getAmountPaid();
$httpBackend.flush();
expect(receipt.amountPaid).toEqual(20);
});
});
describe('responseHandler()', () => {
it('should make an http POST query and then call to the parent responseHandler() method', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
controller.$params = {id: 101};
$httpBackend.expect('POST', `Receipts`,).respond({id: 1});
controller.responseHandler('accept');
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
});
});

View File

@ -68,25 +68,33 @@
<span
vn-click-stop="workerDescriptor.show($event, balance.workerFk)"
class="link">
{{::balance.userNickname}}
{{::balance.userName}}
</span>
</vn-td>
<vn-td expand>
<div ng-show="::balance.ref">
<span
ng-if="balance.isInvoice"
title="{{'BILL' | translate: {ref: balance.ref} }}"
vn-click-stop="$ctrl.showInvoiceOutDescriptor($event, balance)"
class="link">
{{'BILL' | translate: {ref: balance.ref} }}
</span>
<span
ng-if="!balance.isInvoice"
title="{{::balance.ref}}">
{{::balance.ref}}
</span>
</div>
</vn-td>
<vn-td-editable disabled="balance.isInvoice || !$ctrl.isAdministrative" expand>
<text>
<div ng-show="::balance.description">
<span
ng-if="balance.isInvoice"
title="{{'BILL' | translate: {ref: balance.description} }}"
vn-click-stop="$ctrl.showInvoiceOutDescriptor($event, balance)"
class="link">
{{'BILL' | translate: {ref: balance.description} }}
</span>
<span
ng-if="!balance.isInvoice"
title="{{::balance.description}}">
{{balance.description}}
</span>
</div>
</text>
<field>
<vn-textfield vn-acl="administrative" class="dense" vn-focus
ng-model="balance.description"
on-change="$ctrl.changeDescription(balance)">
</vn-textfield>
</field>
</vn-td-editable>
<vn-td number>{{::balance.bankFk}}</vn-td>
<vn-td number expand>{{::balance.debit | currency: 'EUR':2}}</vn-td>
<vn-td number expand>{{::balance.credit | currency: 'EUR':2}}</vn-td>

View File

@ -39,6 +39,10 @@ class Controller extends Section {
this.getBalances();
}
get isAdministrative() {
return this.aclService.hasAny(['administrative']);
}
getData() {
return this.$.model.applyFilter(null, {
clientId: this.$params.id,
@ -58,7 +62,7 @@ class Controller extends Section {
return balance.companyFk === selectedCompany;
});
return currentBalance.amount;
return currentBalance && currentBalance.amount;
}
getBalances() {
@ -79,6 +83,13 @@ class Controller extends Section {
this.$.invoiceOutDescriptor.show(event.target, balance.id);
}
changeDescription(balance) {
const params = {description: balance.description};
const endpoint = `Receipts/${balance.id}`;
this.$http.patch(endpoint, params)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
}
Controller.$inject = ['$element', '$scope'];

View File

@ -3,10 +3,12 @@ import './index';
describe('Client', () => {
describe('Component vnClientBalanceIndex', () => {
let controller;
let $httpBackend;
beforeEach(ngModule('client'));
beforeEach(inject(($componentController, $rootScope) => {
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
let $scope = $rootScope.$new();
const $element = angular.element('<vn-client-balance-index></vn-client-balance-index>');
controller = $componentController('vnClientBalanceIndex', {$element, $scope});
@ -133,5 +135,21 @@ describe('Client', () => {
expect(controller.getBalances).toHaveBeenCalledWith();
});
});
describe('changeDescription()', () => {
it('should make an http PATCH query', () => {
const expectedParams = {description: 'Web'};
$httpBackend.expect('PATCH', `Receipts/1`, expectedParams).respond(200);
controller.changeDescription({
id: 1,
description: 'Web',
accountingType: {
description: 'Cash'
}
});
$httpBackend.flush();
});
});
});
});

View File

@ -1,28 +0,0 @@
module.exports = Self => {
Self.remoteMethod('getLastEntries', {
description: 'Returns last entries',
accessType: 'READ',
accepts: [{
arg: 'filter',
type: 'object',
required: true,
description: 'itemFk, id'
}],
returns: {
type: 'Array',
root: true
},
http: {
path: `/getLastEntries`,
verb: 'GET'
}
});
Self.getLastEntries = async filter => {
let where = filter.where;
let query = `CALL vn.itemLastEntries(?, ?)`;
let [lastEntries] = await Self.rawSql(query, [where.itemFk, where.date]);
return lastEntries;
};
};

View File

@ -0,0 +1,62 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('lastEntriesFilter', {
description: 'Returns last entries',
accessType: 'READ',
accepts: [{
arg: 'filter',
type: 'object',
required: true,
description: 'itemFk, id'
}],
returns: {
type: 'Array',
root: true
},
http: {
path: `/lastEntriesFilter`,
verb: 'GET'
}
});
Self.lastEntriesFilter = async filter => {
const conn = Self.dataSource.connector;
const stmt = new ParameterizedSQL(
`SELECT
w.id AS warehouseFk,
w.name AS warehouse,
tr.landed,
b.id AS buyFk,
b.entryFk,
b.isIgnored,
b.price2,
b.price3,
b.stickers,
b.packing,
b.grouping,
b.groupingMode,
b.weight,
i.stems,
b.quantity,
b.buyingValue,
b.packageFk ,
s.id AS supplierFk,
s.name AS supplier
FROM itemType it
RIGHT JOIN (entry e
LEFT JOIN supplier s ON s.id = e.supplierFk
RIGHT JOIN buy b ON b.entryFk = e.id
LEFT JOIN item i ON i.id = b.itemFk
LEFT JOIN ink ON ink.id = i.inkFk
LEFT JOIN travel tr ON tr.id = e.travelFk
LEFT JOIN warehouse w ON w.id = tr.warehouseInFk
LEFT JOIN origin o ON o.id = i.originFk
) ON it.id = i.typeFk
LEFT JOIN edi.ekt ek ON b.ektFk = ek.id`);
stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
};
};

View File

@ -1,22 +0,0 @@
const app = require('vn-loopback/server/server');
describe('item getLastEntries()', () => {
it('should return one entry for a given item', async() => {
let date = new Date();
let filter = {where: {itemFk: 1, date: date}};
let result = await app.models.Item.getLastEntries(filter);
expect(result.length).toEqual(1);
});
it('should return five entries for a given item', async() => {
let date = new Date();
date.setMonth(date.getMonth() - 2, 1);
let filter = {where: {itemFk: 1, date: date}};
let result = await app.models.Item.getLastEntries(filter);
expect(result.length).toEqual(5);
});
});

View File

@ -0,0 +1,24 @@
const app = require('vn-loopback/server/server');
describe('item lastEntriesFilter()', () => {
const minDate = new Date(value);
minHour.setHours(0, 0, 0, 0);
const maxDate = new Date(value);
maxHour.setHours(23, 59, 59, 59);
it('should return one entry for a given item', async() => {
const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}};
const result = await app.models.Item.lastEntriesFilter(filter);
expect(result.length).toEqual(1);
});
it('should return five entries for a given item', async() => {
minDate.setMonth(minDate.getMonth() - 2, 1);
const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}};
const result = await app.models.Item.lastEntriesFilter(filter);
expect(result.length).toEqual(5);
});
});

View File

@ -5,7 +5,7 @@ module.exports = Self => {
require('../methods/item/clone')(Self);
require('../methods/item/updateTaxes')(Self);
require('../methods/item/getBalance')(Self);
require('../methods/item/getLastEntries')(Self);
require('../methods/item/lastEntriesFilter')(Self);
require('../methods/item/getSummary')(Self);
require('../methods/item/getCard')(Self);
require('../methods/item/regularize')(Self);

View File

@ -109,6 +109,14 @@
ng-model="$ctrl.item.density"
rule>
</vn-input-number>
<vn-input-number
vn-one
min="0"
step="0.01"
label="Compression"
ng-model="$ctrl.item.compression"
rule>
</vn-input-number>
<vn-input-number
vn-one
min="0"

View File

@ -1,11 +1,15 @@
<vn-crud-model
vn-id="model"
url="Items/getLastEntries"
url="Items/lastEntriesFilter"
filter="::$ctrl.filter"
data="entries"
auto-load="false">
auto-load="true"
order="landed DESC, buyFk DESC"
limit="20">
</vn-crud-model>
<vn-vertical>
<vn-data-viewer
model="model"
class="vn-mb-xl vn-w-xl">
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
@ -20,8 +24,8 @@
<vn-thead>
<vn-tr>
<vn-th vn-tooltip="Ignored" center>Ig</vn-th>
<vn-th>Warehouse</vn-th>
<vn-th>Landed</vn-th>
<vn-th field="warehouseFk">Warehouse</vn-th>
<vn-th field="landed">Landed</vn-th>
<vn-th number>Entry</vn-th>
<vn-th number vn-tooltip="Price Per Unit">P.P.U</vn-th>
<vn-th number vn-tooltip="Price Per Package">P.P.P</vn-th>
@ -29,11 +33,11 @@
<vn-th number>Packing</vn-th>
<vn-th number>Grouping</vn-th>
<vn-th number class="expendable">Stems</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th field="quantity" number>Quantity</vn-th>
<vn-th number class="expendable">Cost</vn-th>
<vn-th number>Kg.</vn-th>
<vn-th number>Cube</vn-th>
<vn-th class="expendable">Provider</vn-th>
<vn-th field="packageFk" number>Cube</vn-th>
<vn-th field="supplierFk" class="expendable">Provider</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
@ -70,6 +74,30 @@
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-vertical>
</vn-data-viewer>
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
<slot-menu>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.filterBySelection()">
Filter by selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.excludeSelection()">
Exclude selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.removeFilter()" >
Remove filter
</vn-item>
<vn-item translate
ng-click="contextmenu.removeAllFilters()" >
Remove all filters
</vn-item>
</slot-menu>
</vn-contextmenu>

View File

@ -6,17 +6,23 @@ class Controller extends Section {
constructor($element, $) {
super($element, $);
let defaultDate = new Date();
defaultDate.setDate(defaultDate.getDate() - 75);
defaultDate.setHours(0, 0, 0, 0);
const from = new Date();
from.setDate(from.getDate() - 75);
from.setHours(0, 0, 0, 0);
const to = new Date();
to.setDate(to.getDate() + 10);
to.setHours(23, 59, 59, 59);
this.filter = {
where: {
itemFk: this.$params.id,
date: defaultDate
shipped: {
between: [from, to]
}
}
};
this._date = defaultDate;
this._date = from;
}
set date(value) {
@ -31,6 +37,32 @@ class Controller extends Section {
get date() {
return this._date;
}
exprBuilder(param, value) {
switch (param) {
case 'id':
case 'quantity':
case 'packageFk':
return {[`b.${param}`]: value};
case 'supplierFk':
return {[`s.id`]: value};
case 'warehouseFk':
return {'tr.warehouseInFk': value};
case 'landed':
return {'tr.landed': {
between: this.dateRange(value)}
};
}
}
dateRange(value) {
const minHour = new Date(value);
minHour.setHours(0, 0, 0, 0);
const maxHour = new Date(value);
maxHour.setHours(23, 59, 59, 59);
return [minHour, maxHour];
}
}
Controller.$inject = ['$element', '$scope'];

View File

@ -56,12 +56,14 @@
label="For me"
ng-model="filter.mine">
</vn-check>
<vn-check
<vn-autocomplete
vn-one
triple-state="true"
label="Confirmed"
ng-model="filter.isOk">
</vn-check>
ng-model="filter.state"
data="$ctrl.states"
value-field="code"
label="State">
<tpl-item>{{name}}</tpl-item>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>

View File

@ -1,7 +1,19 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
class Controller extends SearchPanel {
constructor($element, $) {
super($element, $);
this.states = [
{code: 'pending', name: this.$t('Pending')},
{code: 'accepted', name: this.$t('Accepted')},
{code: 'denied', name: this.$t('Denied')}
];
}
}
ngModule.vnComponent('vnRequestSearchPanel', {
template: require('./index.html'),
controller: SearchPanel
controller: Controller
});

View File

@ -24,14 +24,15 @@
<vn-tr>
<vn-th field="ticketFk" number>Ticket ID</vn-th>
<vn-th field="shipped" expand>Shipped</vn-th>
<vn-th field="description" expand>Description</vn-th>
<vn-th field="description" filter-enabled="false" expand>Description</vn-th>
<vn-th field="quantity" number editable>Requested</vn-th>
<vn-th field="price" number>Price</vn-th>
<vn-th field="atenderNickname">Atender</vn-th>
<vn-th field="itemFk">Item</vn-th>
<vn-th field="attenderName">Atender</vn-th>
<vn-th>Item</vn-th>
<vn-th field="saleQuantity">Achieved</vn-th>
<vn-th field="description">Concept</vn-th>
<vn-th field="description" filter-enabled="false">Concept</vn-th>
<vn-th field="isOk">State</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
@ -83,7 +84,7 @@
{{request.itemDescription}}
</span>
</vn-td>
<vn-td>{{$ctrl.getState(request.isOk)}}</vn-td>
<vn-td translate>{{$ctrl.getState(request.isOk)}}</vn-td>
<vn-td>
<vn-icon
ng-if="request.response.length"
@ -129,3 +130,28 @@
<button response="accept" translate>Save</button>
</tpl-buttons>
</vn-dialog>
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
<slot-menu>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.filterBySelection()">
Filter by selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.excludeSelection()">
Exclude selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.removeFilter()" >
Remove filter
</vn-item>
<vn-item translate
ng-click="contextmenu.removeAllFilters()" >
Remove all filters
</vn-item>
</slot-menu>
</vn-contextmenu>

View File

@ -17,18 +17,19 @@ export default class Controller extends Section {
this.filterParams = {
mine: true,
from: today,
to: nextWeek
to: nextWeek,
state: 'pending'
};
}
}
getState(isOk) {
if (isOk === null)
return 'Nueva';
return 'Pending';
else if (isOk)
return 'Aceptada';
return 'Accepted';
else
return 'Denegada';
return 'Denied';
}
confirmRequest(request) {
@ -92,6 +93,31 @@ export default class Controller extends Section {
this.vnApp.showSuccess(this.$t('Data saved!'));
});
}
exprBuilder(param, value) {
switch (param) {
case 'ticketFk':
case 'quantity':
case 'price':
case 'isOk':
return {[`tr.${param}`]: value};
case 'attenderName':
return {[`ua.name`]: value};
case 'shipped':
return {'t.shipped': {
between: this.dateRange(value)}
};
}
}
dateRange(value) {
const minHour = new Date(value);
minHour.setHours(0, 0, 0, 0);
const maxHour = new Date(value);
maxHour.setHours(23, 59, 59, 59);
return [minHour, maxHour];
}
}
ngModule.vnComponent('vnItemRequest', {

View File

@ -24,17 +24,17 @@ describe('Item', () => {
let isOk = null;
let result = controller.getState(isOk);
expect(result).toEqual('Nueva');
expect(result).toEqual('Pending');
isOk = 1;
result = controller.getState(isOk);
expect(result).toEqual('Aceptada');
expect(result).toEqual('Accepted');
isOk = 0;
result = controller.getState(isOk);
expect(result).toEqual('Denegada');
expect(result).toEqual('Denied');
});
});

View File

@ -4,3 +4,6 @@ Buy requests: Peticiones de compra
Search request by id or alias: Buscar peticiones por identificador o alias
Requested: Solicitado
Achieved: Conseguido
Pending: Pendiente
Accepted: Aceptada
Denied: Rechazada

View File

@ -136,14 +136,10 @@ module.exports = Self => {
let stmts = [];
let stmt;
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.filter');
stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.filter
(INDEX (id))
ENGINE = MEMORY
SELECT
`SELECT
o.id,
o.total,
o.date_send landed,
o.date_make created,
o.customer_id clientFk,
@ -178,36 +174,13 @@ module.exports = Self => {
}
stmt.merge(conn.makeWhere(filter.where));
stmt.merge({
sql: `GROUP BY o.id`
});
stmt.merge(`GROUP BY o.id`);
stmt.merge(conn.makePagination(filter));
stmts.push(stmt);
stmts.push(`
CREATE TEMPORARY TABLE tmp.order
(INDEX (orderFk))
ENGINE = MEMORY
SELECT id AS orderFk
FROM tmp.filter`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
stmts.push('CALL hedera.order_getTotal()');
stmt = new ParameterizedSQL(
`SELECT f.*, ot.*
FROM tmp.filter f
LEFT JOIN tmp.orderTotal ot ON ot.orderFk = f.id`);
const orderIndex = stmts.push(stmt) - 1;
stmts.push(`
DROP TEMPORARY TABLE
tmp.order,
tmp.orderTotal,
tmp.filter`);
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return result[orderIndex];
return result;
};
};

View File

@ -79,6 +79,9 @@
"mysql": {
"columnName": "confirm_date"
}
},
"total": {
"type": "Number"
}
},
"relations": {

View File

@ -24,3 +24,4 @@ Search order by id: Buscar el pedido por identificador
order: pedido
Confirm lines: Confirmar las lineas
Confirm: Confirmar
Real hour: Hora real

View File

@ -8,3 +8,4 @@ Application: Aplicación
SalesPerson: Comercial
Order confirmed: Pedido confirmado
Show empty: Mostrar vacías
Search orders by id: Buscar pedido por id

View File

@ -29,20 +29,24 @@ module.exports = Self => {
e.ticketFk,
e.isBox,
e.workerFk,
i1.name namePackage,
i1.name packageItemName,
e.counter,
e.checked,
i2.name nameBox,
i2.name freightItemName,
e.itemFk,
u.nickname userNickname,
e.created,
e.externalId
e.externalId,
i3.name packagingName,
i3.id packagingItemFk,
e.packagingFk
FROM
vn.expedition e
LEFT JOIN vn.item i2 ON i2.id = e.itemFk
INNER JOIN vn.item i1 ON i1.id = e.isBox
LEFT JOIN vn.worker w ON w.id = e.workerFk
LEFT JOIN account.user u ON u.id = w.userFk
LEFT JOIN vn.packaging p ON p.id = e.packagingFk
LEFT JOIN vn.item i3 ON i3.id = p.itemFk
LEFT JOIN account.user u ON u.id = e.workerFk
`);
stmt.merge(Self.buildSuffix(filter, 'e'));

View File

@ -44,8 +44,8 @@ module.exports = Self => {
type: 'Date',
description: `Date to`
}, {
arg: 'isOk',
type: 'Boolean',
arg: 'state',
type: 'String',
description: `Search request by request state`
}
],
@ -77,8 +77,13 @@ module.exports = Self => {
return {'t.id': value};
case 'attenderFk':
return {'tr.attenderFk': value};
case 'isOk':
return {'tr.isOk': value};
case 'state':
switch (value) {
case 'pending':
return {'tr.isOk': null};
default:
return {'tr.isOk': value};
}
case 'clientFk':
return {'t.clientFk': value};
case 'from':

View File

@ -24,12 +24,6 @@
},
"counter": {
"type": "Number"
},
"checked": {
"type": "Number"
},
"externalId": {
"type": "Number"
}
},
"relations": {
@ -43,7 +37,7 @@
"model": "agency-mode",
"foreignKey": "agencyModeFk"
},
"item": {
"packageItem": {
"type": "belongsTo",
"model": "Item",
"foreignKey": "itemFk"
@ -58,10 +52,15 @@
"model": "TicketPackaging",
"foreignKey": "ticketFk"
},
"box": {
"freightItem": {
"type": "belongsTo",
"model": "Item",
"foreignKey": "isBox"
},
"packaging": {
"type": "belongsTo",
"model": "Package",
"foreignKey": "packagingFk"
}
}
}

View File

@ -155,7 +155,7 @@ class Controller extends Component {
let query = `Clients/${value}`;
this.$http.get(query).then(res => {
if (res.data)
this.ticket.addressFk = res.data.defaultAddressFk;
this.addressId = res.data.defaultAddressFk;
});
}

View File

@ -8,7 +8,6 @@ class Controller extends Descriptor {
set ticket(value) {
this.entity = value;
this.isTicketEditable();
}
get entity() {
@ -18,6 +17,7 @@ class Controller extends Descriptor {
set entity(value) {
super.entity = value;
this.canStowaway();
this.isTicketEditable();
if (value && this.$params.sendSMS)
this.showSMSDialog();
@ -45,7 +45,8 @@ class Controller extends Descriptor {
}
isTicketEditable() {
this.$http.get(`Tickets/${this.$state.params.id}/isEditable`).then(res => {
if (!this.ticket) return;
this.$http.get(`Tickets/${this.id}/isEditable`).then(res => {
this.isEditable = res.data;
});
}

View File

@ -14,12 +14,10 @@
<vn-tr>
<vn-th></vn-th>
<vn-th field="itemFk" number>Expedition</vn-th>
<vn-th field="itemFk" number>Envialia</vn-th>
<vn-th field="itemFk" number>Item</vn-th>
<vn-th field="name">Name</vn-th>
<vn-th field="isBox">Package type</vn-th>
<vn-th field="counter" number>Counter</vn-th>
<vn-th field="checked" number>Checked</vn-th>
<vn-th field="worker">Worker</vn-th>
<vn-th field="created">Created</vn-th>
</vn-tr>
@ -33,18 +31,16 @@
</vn-icon-button>
</vn-td>
<vn-td number>{{expedition.id | zeroFill:6}}</vn-td>
<vn-td number>{{expedition.externalId | zeroFill:6}}</vn-td>
<vn-td number>
<span
ng-class="{link: expedition.itemFk}"
ng-click="itemDescriptor.show($event, expedition.itemFk)">
{{expedition.itemFk | zeroFill:6}}
ng-class="{link: expedition.packagingItemFk}"
ng-click="itemDescriptor.show($event, expedition.packagingItemFk)">
{{expedition.packagingFk}}
</span>
</vn-td>
<vn-td>{{::expedition.namePackage}}</vn-td>
<vn-td>{{::expedition.nameBox}}</vn-td>
<vn-td>{{::expedition.packageItemName}}</vn-td>
<vn-td>{{::expedition.freightItemName}}</vn-td>
<vn-td number>{{::expedition.counter}}</vn-td>
<vn-td number>{{::expedition.checked}}</vn-td>
<vn-td expand>
<span
class="link"

View File

@ -12,4 +12,4 @@ Order id: Id cesta
Grouped States: Estado agrupado
Days onward: Días adelante
With problems: Con problemas
Pending: Pendientes
Pending: Pendiente

54
package-lock.json generated
View File

@ -5824,7 +5824,7 @@
},
"util": {
"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=",
"dev": true,
"requires": {
@ -6786,7 +6786,7 @@
"base": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
"integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=",
"dev": true,
"requires": {
"cache-base": "^1.0.1",
@ -7102,7 +7102,7 @@
},
"browserify-rsa": {
"version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"dev": true,
"requires": {
@ -7162,7 +7162,7 @@
},
"buffer": {
"version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"requires": {
"base64-js": "^1.0.2",
@ -7293,7 +7293,7 @@
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
"integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=",
"dev": true,
"requires": {
"collection-visit": "^1.0.0",
@ -7363,7 +7363,7 @@
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
"requires": {
@ -7507,7 +7507,7 @@
"class-utils": {
"version": "0.3.6",
"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,
"requires": {
"arr-union": "^3.1.0",
@ -8664,7 +8664,7 @@
},
"readable-stream": {
"version": "1.1.14",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"dev": true,
"requires": {
@ -9765,7 +9765,7 @@
},
"file-loader": {
"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==",
"dev": true,
"requires": {
@ -10951,7 +10951,7 @@
"global-modules": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
"integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
"dev": true,
"requires": {
"global-prefix": "^1.0.1",
@ -10988,7 +10988,7 @@
},
"globby": {
"version": "5.0.0",
"resolved": "http://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
"resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
"integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
"dev": true,
"requires": {
@ -13134,7 +13134,7 @@
"is-plain-object": {
"version": "2.0.4",
"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,
"requires": {
"isobject": "^3.0.1"
@ -18514,7 +18514,7 @@
},
"load-json-file": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
@ -19395,7 +19395,7 @@
},
"media-typer": {
"version": "0.3.0",
"resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"mem": {
@ -19420,7 +19420,7 @@
},
"meow": {
"version": "3.7.0",
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
"requires": {
@ -19869,7 +19869,7 @@
},
"multipipe": {
"version": "0.1.2",
"resolved": "http://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
"integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
"dev": true,
"requires": {
@ -20761,7 +20761,7 @@
},
"os-homedir": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true
},
@ -20777,7 +20777,7 @@
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
@ -22342,7 +22342,7 @@
},
"safe-regex": {
"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=",
"dev": true,
"requires": {
@ -22543,7 +22543,7 @@
"dependencies": {
"source-map": {
"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=",
"dev": true,
"requires": {
@ -22991,7 +22991,7 @@
"snapdragon-node": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
"integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=",
"dev": true,
"requires": {
"define-property": "^1.0.0",
@ -23042,7 +23042,7 @@
"snapdragon-util": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
"integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=",
"dev": true,
"requires": {
"kind-of": "^3.2.0"
@ -23326,7 +23326,7 @@
"split-string": {
"version": "3.1.0",
"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,
"requires": {
"extend-shallow": "^3.0.0"
@ -24398,7 +24398,7 @@
},
"through": {
"version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
@ -24599,7 +24599,7 @@
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
"integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=",
"dev": true,
"requires": {
"nopt": "~1.0.10"
@ -24681,7 +24681,7 @@
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
"dev": true
},
@ -26363,7 +26363,7 @@
},
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
},
"xmlchars": {