Merge branch 'dev' of https://git.verdnatura.es/salix into dev
This commit is contained in:
commit
7c3efd40d5
|
@ -97,6 +97,13 @@
|
|||
"description": "Barcode",
|
||||
"icon": "folder"
|
||||
}
|
||||
},{
|
||||
"url" : "/summary",
|
||||
"state": "item.card.summary",
|
||||
"component": "vn-item-summary",
|
||||
"params": {
|
||||
"item": "$ctrl.item"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-one margin-medium-top>
|
||||
<vn-title>Item Barcodes</vn-title>
|
||||
<mg-ajax path="/item/api/ItemBarcodes" options="mgIndex as barcodes"></mg-ajax>
|
||||
<vn-horizontal ng-repeat="barcode in $ctrl.barcodes track by $index">
|
||||
<vn-textfield vn-three label="code" model="barcode.code" vn-acl="buyer, replenisher"></vn-textfield>
|
||||
<vn-one pad-medium-top>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
</mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.botanical"
|
||||
data="$ctrl.item.botanical"
|
||||
form="form"
|
||||
save="patch">
|
||||
</vn-watcher>
|
||||
|
@ -13,20 +13,20 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-title>Botanical</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Botanical" model="$ctrl.botanical.botanical"></vn-textfield>
|
||||
<vn-textfield vn-one label="Botanical" model="$ctrl.item.botanical.botanical"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.botanical.genus"
|
||||
field="$ctrl.botanical.genusFk"
|
||||
initial-data="$ctrl.item.botanical.genus"
|
||||
field="$ctrl.item.botanical.genusFk"
|
||||
url="/item/api/genera"
|
||||
show-field="latin_genus_name"
|
||||
value-field="genus_id"
|
||||
label="Genus">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.botanical.specie"
|
||||
field="$ctrl.botanical.specieFk"
|
||||
initial-data="$ctrl.item.botanical.specie"
|
||||
field="$ctrl.item.botanical.specieFk"
|
||||
url="/item/api/species"
|
||||
show-field="latin_species_name"
|
||||
value-field="specie_id"
|
||||
|
|
|
@ -1,30 +1,8 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class ItemBotanical {
|
||||
constructor($http, $state) {
|
||||
this.$http = $http;
|
||||
this.botanical = {
|
||||
itemFk: $state.params.id
|
||||
};
|
||||
}
|
||||
$onInit() {
|
||||
let filter = {
|
||||
where: {
|
||||
itemFk: this.botanical.itemFk
|
||||
},
|
||||
include: [{relation: 'genus'}, {relation: 'specie'}]
|
||||
};
|
||||
this.$http.get(`/item/api/ItemBotanicals?filter=${JSON.stringify(filter)}`)
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
Object.assign(this.botanical, res.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
ItemBotanical.$inject = ['$http', '$state'];
|
||||
|
||||
ngModule.component('vnItemBotanical', {
|
||||
template: require('./item-botanical.html'),
|
||||
controller: ItemBotanical
|
||||
bindings: {
|
||||
item: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,7 +4,21 @@ class ItemCard {
|
|||
constructor($http, $state) {
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.item = {};
|
||||
}
|
||||
|
||||
_getBotanical() {
|
||||
let filter = {
|
||||
where: {
|
||||
itemFk: this.$state.params.id
|
||||
},
|
||||
include: [{relation: 'genus'}, {relation: 'specie'}]
|
||||
};
|
||||
this.$http.get(`/item/api/ItemBotanicals?filter=${JSON.stringify(filter)}`)
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.item.botanical = res.data[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
|
@ -19,10 +33,14 @@ class ItemCard {
|
|||
{relation: "itemTag", scope: {order: "priority ASC", include: {relation: "tag"}}}
|
||||
]
|
||||
};
|
||||
this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`).then(
|
||||
res => {
|
||||
this.item = res.data;
|
||||
}
|
||||
this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`)
|
||||
.then(
|
||||
res => {
|
||||
if (res.data && res.data.id) {
|
||||
this.item = res.data;
|
||||
this._getBotanical();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,13 @@ describe('Item', () => {
|
|||
controller = $componentController('vnItemCard', {$state: $state});
|
||||
}));
|
||||
|
||||
describe('$onInit()', () => {
|
||||
describe('_getBasicData()', () => {
|
||||
it('should request to patch the propagation of tax status', () => {
|
||||
controller.client = {id: 123, isEqualizated: false};
|
||||
$httpBackend.whenGET('/item/api/Items/undefined?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/undefined?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}');
|
||||
controller.$onInit();
|
||||
controller.item = {id: 123};
|
||||
$httpBackend.whenGET('/item/api/Items/123?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/123?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}');
|
||||
controller._getBasicData();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.item).toEqual({data: 'item'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,4 +12,5 @@ import './history/item-history';
|
|||
import './niche/item-niche';
|
||||
import './botanical/item-botanical';
|
||||
import './barcode/item-barcode';
|
||||
import './summary/item-summary';
|
||||
|
||||
|
|
|
@ -1,5 +1,48 @@
|
|||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Niche</vn-title>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<form name="form" ng-submit="$ctrl.submit()">
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-one margin-medium-top>
|
||||
<vn-title>Item Niches</vn-title>
|
||||
<vn-horizontal ng-repeat="niche in $ctrl.niches track by $index">
|
||||
<vn-autocomplete
|
||||
vn-three
|
||||
initial-data = "niche.warehouse"
|
||||
field = "niche.warehouseFk"
|
||||
data = "$ctrl.warehouses"
|
||||
show-field = "name"
|
||||
value-field = "id"
|
||||
label = "Warehouse"
|
||||
order = "name ASC"
|
||||
vn-acl="buyer, replenisher">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-three label="code"
|
||||
model="niche.code"
|
||||
vn-acl="buyer, replenisher">
|
||||
</vn-textfield>
|
||||
<vn-one pad-medium-top>
|
||||
<vn-icon
|
||||
vn-acl="buyer, replenisher"
|
||||
pointer
|
||||
medium-grey
|
||||
icon="remove_circle_outline"
|
||||
ng-click="$ctrl.removeNiche($index)">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
vn-acl="buyer, replenisher"
|
||||
pointer
|
||||
margin-medium-left
|
||||
orange
|
||||
icon="add_circle"
|
||||
ng-if = "niche.showAddIcon"
|
||||
ng-click="$ctrl.addNiche()">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
|
|
|
@ -1,5 +1,142 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($state, $scope, $http, $q, $translate, vnApp) {
|
||||
this.$state = $state;
|
||||
this.$scope = $scope;
|
||||
this.$http = $http;
|
||||
this.$q = $q;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
|
||||
this.warehouses = [];
|
||||
this.niches = [];
|
||||
this.removedNiches = [];
|
||||
this.oldNiches = {};
|
||||
}
|
||||
|
||||
_setIconAdd() {
|
||||
if (this.niches.length) {
|
||||
this.niches.map(element => {
|
||||
element.showAddIcon = false;
|
||||
return true;
|
||||
});
|
||||
this.niches[this.niches.length - 1].showAddIcon = true;
|
||||
} else {
|
||||
this.addNiche();
|
||||
}
|
||||
}
|
||||
|
||||
_setDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setDirty();
|
||||
}
|
||||
}
|
||||
_unsetDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setPristine();
|
||||
}
|
||||
}
|
||||
|
||||
addNiche() {
|
||||
this.niches.push({code: null, itemFk: this.$state.params.id, showAddIcon: true});
|
||||
this._setIconAdd();
|
||||
}
|
||||
|
||||
removeNiche(index) {
|
||||
let item = this.niches[index];
|
||||
if (item) {
|
||||
this.niches.splice(index, 1);
|
||||
this._setIconAdd();
|
||||
if (item.id) {
|
||||
this.removedNiches.push(item.id);
|
||||
this._setDirtyForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_equalNiches(oldNiche, newNiche) {
|
||||
return oldNiche.id === newNiche.id && oldNiche.code === newNiche.code && oldNiche.warehouseFk === newNiche.warehouseFk;
|
||||
}
|
||||
|
||||
submit() {
|
||||
let warehousesDefined = [];
|
||||
let repeatedWarehouse = false;
|
||||
let canSubmit;
|
||||
let nichesObj = {
|
||||
delete: this.removedNiches,
|
||||
create: [],
|
||||
update: []
|
||||
};
|
||||
this.niches.forEach(niche => {
|
||||
let isNewNiche = !niche.id;
|
||||
|
||||
if (warehousesDefined.indexOf(niche.warehouseFk) !== -1) {
|
||||
repeatedWarehouse = true;
|
||||
return;
|
||||
}
|
||||
warehousesDefined.push(niche.warehouseFk);
|
||||
|
||||
if (isNewNiche) {
|
||||
nichesObj.create.push(niche);
|
||||
}
|
||||
|
||||
if (!isNewNiche && !this._equalNiches(this.oldNiches[niche.id], niche)) {
|
||||
nichesObj.update.push(niche);
|
||||
}
|
||||
});
|
||||
|
||||
if (repeatedWarehouse) {
|
||||
return this.vnApp.showMessage(this.$translate.instant('The niche must be unique'));
|
||||
}
|
||||
canSubmit = nichesObj.update.length > 0 || nichesObj.create.length > 0 || nichesObj.delete.length > 0;
|
||||
|
||||
if (canSubmit) {
|
||||
return this.$http.post(`/item/api/ItemNiches/crudItemNiches`, nichesObj).then(() => {
|
||||
this.getNiches();
|
||||
this._unsetDirtyForm();
|
||||
});
|
||||
}
|
||||
this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
}
|
||||
|
||||
setOldNiches(response) {
|
||||
this._setIconAdd();
|
||||
response.data.forEach(niche => {
|
||||
this.oldNiches[niche.id] = Object.assign({}, niche);
|
||||
});
|
||||
}
|
||||
|
||||
getWarehouse(id, warehouses) {
|
||||
return warehouses.find(warehouse => warehouse.id === id);
|
||||
}
|
||||
|
||||
getNiches() {
|
||||
let filter = {
|
||||
where: {itemFk: this.$state.params.id},
|
||||
include: {relation: 'warehouse'}
|
||||
};
|
||||
this.$http.get(`/item/api/ItemNiches?filter=${JSON.stringify(filter)}`).then(response => {
|
||||
this.niches = response.data;
|
||||
this.setOldNiches(response);
|
||||
});
|
||||
}
|
||||
|
||||
getWarehouses() {
|
||||
this.$http.get(`/item/api/Warehouses`).then(response => {
|
||||
this.warehouses = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.getNiches();
|
||||
this.getWarehouses();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$state', '$scope', '$http', '$q', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnItemNiche', {
|
||||
template: require('./item-niche.html')
|
||||
template: require('./item-niche.html'),
|
||||
controller: Controller
|
||||
});
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
import './item-niche.js';
|
||||
|
||||
describe('Item', () => {
|
||||
describe('Component vnItemNiche', () => {
|
||||
let $componentController;
|
||||
let $state;
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('item');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$state = _$state_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnItemNiche', {$state: $state});
|
||||
}));
|
||||
|
||||
describe('add / remove niche()', () => {
|
||||
it('should add one empty niche into controller niches collection and call _setIconAdd()', () => {
|
||||
controller.niches = [];
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
controller.addNiche();
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.niches.length).toEqual(1);
|
||||
expect(controller.niches[0].id).toBe(undefined);
|
||||
expect(controller.niches[0].showAddIcon).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should remove a niche that occupies the position in the index given and call _setIconAdd()', () => {
|
||||
let index = 2;
|
||||
controller.niches = [
|
||||
{id: 1, warehouseFk: 1, code: '1111', showAddIcon: false},
|
||||
{id: 2, warehouseFk: 2, code: '2222', showAddIcon: false},
|
||||
{id: 3, warehouseFk: 3, code: '3333', showAddIcon: true}
|
||||
];
|
||||
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
|
||||
controller.removeNiche(index);
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.niches.length).toEqual(2);
|
||||
expect(controller.niches[0].showAddIcon).toBeFalsy();
|
||||
expect(controller.niches[1].showAddIcon).toBeTruthy();
|
||||
expect(controller.niches[index]).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_equalNiches()', () => {
|
||||
it('should return true if two niches are equals independent of control attributes', () => {
|
||||
let niche1 = {id: 1, warehouseFk: 1, code: '1111', showAddIcon: true};
|
||||
let niche2 = {id: 1, warehouseFk: 1, code: '1111', showAddIcon: false};
|
||||
let equals = controller._equalNiches(niche2, niche1);
|
||||
|
||||
expect(equals).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if two niches aint equals independent of control attributes', () => {
|
||||
let niche1 = {id: 1, warehouseFk: 1, code: '1111', showAddIcon: true};
|
||||
let niche2 = {id: 1, warehouseFk: 1, code: '2222', showAddIcon: true};
|
||||
let equals = controller._equalNiches(niche2, niche1);
|
||||
|
||||
expect(equals).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get Niches / Warehouses', () => {
|
||||
it('should perform a GET query to receive the item niches', () => {
|
||||
let res = [{id: 1, warehouseFk: 1, code: '1111'}];
|
||||
|
||||
$httpBackend.when('GET', `/item/api/ItemNiches?filter={"where":{},"include":{"relation":"warehouse"}}`).respond(res);
|
||||
$httpBackend.expectGET(`/item/api/ItemNiches?filter={"where":{},"include":{"relation":"warehouse"}}`);
|
||||
controller.getNiches();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should perform a GET query to receive the all warehouses', () => {
|
||||
let res = [
|
||||
{id: 1, warehouseFk: 1, name: 'warehouse one'},
|
||||
{id: 2, warehouseFk: 2, name: 'warehouse two'}
|
||||
];
|
||||
|
||||
$httpBackend.when('GET', `/item/api/Warehouses`).respond(res);
|
||||
$httpBackend.expectGET(`/item/api/Warehouses`);
|
||||
controller.getWarehouses();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
|
||||
describe('submit()', () => {
|
||||
it("should return an error message 'The niche must be unique' when the niche code isnt unique", () => {
|
||||
spyOn(controller.vnApp, 'showMessage').and.callThrough();
|
||||
controller.niches = [
|
||||
{warehouseFk: 1, code: 123454, itemFk: 1, id: 1},
|
||||
{warehouseFk: 1, code: 123454, itemFk: 1}
|
||||
];
|
||||
controller.oldNiches = {1: {warehouseFk: 1, id: 1, code: 123454, itemFk: 1}};
|
||||
controller.submit();
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('The niche must be unique');
|
||||
});
|
||||
|
||||
it("should perfom a query to delete niches", () => {
|
||||
controller.oldNiches = {1: {id: 1, warehouseFk: 1, code: '1111'}};
|
||||
controller.niches = [];
|
||||
controller.removedNiches = [1];
|
||||
|
||||
$httpBackend.when('GET', `/item/api/ItemNiches?filter={"where":{},"include":{"relation":"warehouse"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemNiches/crudItemNiches`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should perfom a query to update niches", () => {
|
||||
controller.niches = [{id: 1, warehouseFk: 1, code: '2222'}];
|
||||
controller.oldNiches = {1: {id: 1, warehouseFk: 1, code: '1111'}};
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemNiches?filter={"where":{},"include":{"relation":"warehouse"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemNiches/crudItemNiches`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should perfom a query to create new niche", () => {
|
||||
controller.niches = [{warehouseFk: 1, code: 1111, itemFk: 1}];
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemNiches?filter={"where":{},"include":{"relation":"warehouse"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemNiches/crudItemNiches`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should return a message 'No changes to save' when there are no changes to apply", () => {
|
||||
spyOn(controller.vnApp, 'showMessage').and.callThrough();
|
||||
controller.oldNiches = [
|
||||
{warehouseFk: 1, code: 1, itemFk: 1, id: 1},
|
||||
{warehouseFk: 2, code: 2, itemFk: 1, id: 2}
|
||||
];
|
||||
controller.niches = [];
|
||||
controller.submit();
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('No changes to save');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,56 @@
|
|||
<vn-card>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-horizontal>
|
||||
<vn-one margin-medium>
|
||||
<img
|
||||
ng-src="http://verdnatura.es/vn-image-data/catalog/200x200/{{$ctrl.item.image}}"
|
||||
zoom-image="http://verdnatura.es/vn-image-data/catalog/900x900/{{$ctrl.item.image}}" on-error-src/>
|
||||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<vn-vertical>
|
||||
<h5 translate>Basic data</h5>
|
||||
<p><span translate>Name</span>: <b>{{::$ctrl.item.name}}</b></p>
|
||||
<p><span translate>Type</span>: <b>{{::$ctrl.item.itemType.name}}</b></p>
|
||||
<p><span translate>Intrastat</span>: <b>{{::$ctrl.item.intrastat.description}}</b></p>
|
||||
<p><span translate>Relevancy</span>: <b>{{::$ctrl.item.relevancy}}</b></p>
|
||||
<p><span translate>Origin</span>: <b>{{::$ctrl.item.origin.name}}</b></p>
|
||||
<p><span translate>Expence</span>: <b>{{::$ctrl.item.expence.name}}</b></p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<vn-vertical>
|
||||
<h5 translate>Tags</h5>
|
||||
<p ng-repeat="tag in $ctrl.tags track by tag.id">
|
||||
<span translate>{{tag.tag.name}}</span>: <b>{{tag.value}}</b>
|
||||
</p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-one margin-medium>
|
||||
<vn-vertical>
|
||||
<h5 translate>Nicho</h5>
|
||||
<p><span translate>Name</span>: <b>{{::$ctrl.item.name}}</b></p>
|
||||
<p><span translate>Name</span>: <b>{{::$ctrl.item.name}}</b></p>
|
||||
<p><span translate>Name</span>: <b>{{::$ctrl.item.name}}</b></p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<vn-vertical>
|
||||
<h5 translate>Botanical</h5>
|
||||
<p><span translate>Botanical</span>: <b>{{::$ctrl.item.botanical.botanical}}</b></p>
|
||||
<p><span translate>Genus</span>: <b>{{::$ctrl.item.botanical.genus.latin_genus_name}}</b></p>
|
||||
<p><span translate>Specie</span>: <b>{{::$ctrl.item.botanical.specie.latin_species_name}}</b></p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<vn-vertical>
|
||||
<h5 translate>Barcode</h5>
|
||||
<p ng-repeat="barcode in $ctrl.barcodes track by $index">
|
||||
<b>{{::$ctrl.barcode.code}}</b>
|
||||
</p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
|
@ -0,0 +1,62 @@
|
|||
import ngModule from '../module';
|
||||
import './style.scss';
|
||||
|
||||
class ItemSummary {
|
||||
constructor($http) {
|
||||
this.$http = $http;
|
||||
}
|
||||
|
||||
_getTags() {
|
||||
let filter = {
|
||||
where: {
|
||||
itemFk: this.item.id
|
||||
}
|
||||
};
|
||||
this.tags = [];
|
||||
this.$http.get(`/item/api/ItemTags?filter=${JSON.stringify(Object.assign({}, filter, {include: {relation: 'tag'}}))}`).then(res => {
|
||||
this.tags = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
_getBotanical() {
|
||||
let filter = {
|
||||
include: [{relation: 'genus'}, {relation: 'specie'}]
|
||||
};
|
||||
this.item.botanical = {};
|
||||
this.$http.get(`/item/api/ItemBotanicals/${this.item.id}/?filter=${JSON.stringify(filter)}`)
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.item.botanical = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_getBarcodes() {
|
||||
let filter = {
|
||||
where: {
|
||||
itemFk: this.item.id
|
||||
}
|
||||
};
|
||||
this.barcodes = [];
|
||||
this.$http.get(`/item/api/ItemBarcodes?filter=${JSON.stringify(filter)}`).then(response => {
|
||||
this.barcodes = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
$onChanges() {
|
||||
if (this.item && this.item.id) {
|
||||
this._getTags();
|
||||
if (!this.item.botanical)
|
||||
this._getBotanical();
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemSummary.$inject = ['$http'];
|
||||
|
||||
ngModule.component('vnItemSummary', {
|
||||
template: require('./item-summary.html'),
|
||||
controller: ItemSummary,
|
||||
bindings: {
|
||||
item: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
@import "../../../salix/src/styles/colors";
|
||||
|
||||
vn-item-summary{
|
||||
h5 {
|
||||
border-bottom: 2px solid $color-orange;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
}
|
|
@ -4,28 +4,27 @@
|
|||
<vn-vertical pad-medium>
|
||||
<vn-horizontal vn-one margin-large-bottom class="locator-header">
|
||||
<vn-title vn-one><span translate>Finder</span></vn-title>
|
||||
|
||||
<vn-searchbar vn-two
|
||||
<vn-searchbar
|
||||
vn-two
|
||||
index="index"
|
||||
on-search="$ctrl.searchTickets(index.filter)"
|
||||
advanced="true"
|
||||
popover="vn-production-filter-panel"
|
||||
ignore-keys = "['page', 'size', 'search', 'warehouseFk']"
|
||||
data ="$ctrl.sharedData"
|
||||
>
|
||||
data ="$ctrl.sharedData">
|
||||
</vn-searchbar>
|
||||
|
||||
<vn-one vn-horizontal>
|
||||
<vn-one></vn-one>
|
||||
<vn-autocomplete vn-two
|
||||
<vn-autocomplete
|
||||
vn-two
|
||||
initial-value="$ctrl.filter.warehouseFk"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.warehouseFk"
|
||||
url="/production/api/Warehouses/production"
|
||||
on-change = "$ctrl.onChangeWareHouse(item)"
|
||||
label="Store"
|
||||
></vn-autocomplete>
|
||||
label="Store">
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button vn-none pad-ten-top margin-medium-left icon="refresh" ng-click="$ctrl.refreshTickets()"></vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -12,15 +12,14 @@
|
|||
<vn-title>Create Route</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker vn-one label="Date" model="$ctrl.delivery.date"></vn-date-picker>
|
||||
<vn-autocomplete vn-one
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Agency"
|
||||
url="/route/api/Agencies"
|
||||
field="$ctrl.delivery.agency"
|
||||
>
|
||||
field="$ctrl.delivery.agency">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
||||
<vn-autocomplete vn-one
|
||||
field="$ctrl.delivery.driver"
|
||||
url="/route/api/Vehicles/activeDrivers"
|
||||
|
@ -31,10 +30,9 @@
|
|||
url="/route/api/Vehicles/comboVehicles"
|
||||
label="Vehicle"
|
||||
order="tradeMark ASC"
|
||||
filter="{where: {isActive:1, warehouseFk:1}}"
|
||||
></vn-autocomplete>
|
||||
filter="{where: {isActive:1, warehouseFk:1}}">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
label="Zone"
|
||||
field="$ctrl.filter.zone"
|
||||
url="/route/api/Zones"
|
||||
order="printingOrder ASC"
|
||||
></vn-autocomplete>
|
||||
order="printingOrder ASC">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Postcode" model="$ctrl.filter.postcode"></vn-textfield>
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
"description": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -436,4 +436,4 @@ INSERT INTO `vn`.`itemTag`(`id`,`itemFk`,`tagFk`,`value`,`priority`)
|
|||
|
||||
INSERT INTO `vn`.`itemLog` (`id`, `originFk`, `userFk`, `action`, `description`)
|
||||
VALUES
|
||||
('1', '1', '1', 'insert', 'We made an change!');
|
||||
('1', '1', '1', 'insert', 'We made an change!');
|
|
@ -0,0 +1,36 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('crudItemNiches', {
|
||||
description: 'create, update or delete niches',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'niches',
|
||||
type: 'Object',
|
||||
require: true,
|
||||
description: 'object with niches to create, update or delete, Example: {create: [], update: [], delete: []}',
|
||||
http: {source: 'body'}
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/crudItemNiches`,
|
||||
verb: 'post'
|
||||
}
|
||||
});
|
||||
|
||||
Self.crudItemNiches = niches => {
|
||||
let promises = [];
|
||||
|
||||
if (niches.delete && niches.delete.length) {
|
||||
promises.push(Self.destroyAll({id: {inq: niches.delete}}));
|
||||
}
|
||||
if (niches.create.length) {
|
||||
promises.push(Self.create(niches.create));
|
||||
}
|
||||
if (niches.update.length) {
|
||||
niches.update.forEach(niche => {
|
||||
promises.push(Self.upsert(niche));
|
||||
});
|
||||
}
|
||||
return Promise.all(promises);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
const crudItemNiches = require('../crudItemNiches');
|
||||
const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
|
||||
|
||||
describe('Item crudItemNiches()', () => {
|
||||
it('should call the destroyAll method if there are ids in delete Array', done => {
|
||||
let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
|
||||
|
||||
crudItemNiches(self);
|
||||
self.crudItemNiches({
|
||||
delete: [1],
|
||||
create: [],
|
||||
update: []
|
||||
}).then(result => {
|
||||
expect(self.destroyAll).toHaveBeenCalledWith({id: {inq: [1]}});
|
||||
done();
|
||||
})
|
||||
.catch(catchErrors(done));
|
||||
});
|
||||
|
||||
it('should call the create method if there are ids in create Array', done => {
|
||||
let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
|
||||
|
||||
crudItemNiches(self);
|
||||
self.crudItemNiches({
|
||||
delete: [],
|
||||
create: [1],
|
||||
update: []
|
||||
}).then(result => {
|
||||
expect(self.create).toHaveBeenCalledWith([1]);
|
||||
done();
|
||||
})
|
||||
.catch(catchErrors(done));
|
||||
});
|
||||
|
||||
it('should call the upsert method as many times as ids in update Array', done => {
|
||||
let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
|
||||
|
||||
crudItemNiches(self);
|
||||
self.crudItemNiches({
|
||||
delete: [],
|
||||
create: [],
|
||||
update: [1, 2]
|
||||
}).then(result => {
|
||||
expect(self.upsert).toHaveBeenCalledWith(1);
|
||||
expect(self.upsert).toHaveBeenCalledWith(2);
|
||||
expect(self.upsert.calls.count()).toEqual(2);
|
||||
done();
|
||||
})
|
||||
.catch(catchErrors(done));
|
||||
});
|
||||
});
|
|
@ -84,6 +84,11 @@
|
|||
"type": "hasMany",
|
||||
"model": "ItemBarcode",
|
||||
"foreignKey": "itemFk"
|
||||
},
|
||||
"itemNiche": {
|
||||
"type": "hasMany",
|
||||
"model": "ItemNiche",
|
||||
"foreignKey": "itemFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/item/crudItemNiches.js')(Self);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "ItemNiche",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "itemPlacement",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"item": {
|
||||
"type": "belongsTo",
|
||||
"model": "Item",
|
||||
"foreignKey": "itemFk"
|
||||
},
|
||||
"warehouse": {
|
||||
"type": "belongsTo",
|
||||
"model": "Warehouse",
|
||||
"foreignKey": "warehouseFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "Warehouse",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "warehouse",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -35,6 +35,9 @@
|
|||
"Tag": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemNiche": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
@ -47,6 +50,9 @@
|
|||
"ItemPlacement": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Warehouse": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Specie": {
|
||||
"dataSource": "edi"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue