2564-item_priceFixed + e2e #513
|
@ -25,9 +25,11 @@ pipeline {
|
|||
switch (env.BRANCH_NAME) {
|
||||
case 'master':
|
||||
env.NODE_ENV = 'production'
|
||||
env.BACK_REPLICAS = 4
|
||||
break
|
||||
case 'test':
|
||||
env.NODE_ENV = 'test'
|
||||
env.BACK_REPLICAS = 2
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ module.exports = Self => {
|
|||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
if (process.env.NODE_ENV == 'test')
|
||||
throw new UserError(`You can't upload images on the test instance`);
|
||||
throw new UserError(`You can't upload images on the test environment`);
|
||||
|
||||
// Upload file to temporary path
|
||||
const tempContainer = await TempContainer.container(args.collection);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`itemTag_afterUpdate`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`itemTag_afterUpdate`
|
||||
AFTER UPDATE ON `itemTag` FOR EACH ROW
|
||||
trig: BEGIN
|
||||
IF @isTriggerDisabled THEN
|
||||
LEAVE trig;
|
||||
END IF;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.item;
|
||||
CREATE TEMPORARY TABLE tmp.item
|
||||
SELECT NEW.itemFk id;
|
||||
|
||||
CALL item_refreshTags();
|
||||
DROP TEMPORARY TABLE tmp.item;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -8,7 +8,7 @@ services:
|
|||
ports:
|
||||
- 80
|
||||
deploy:
|
||||
replicas: 3
|
||||
replicas: 2
|
||||
back:
|
||||
image: registry.verdnatura.es/salix-back:${BRANCH_NAME:?}
|
||||
build: .
|
||||
|
@ -30,7 +30,7 @@ services:
|
|||
- /mnt/storage/dms:/var/lib/salix/dms
|
||||
- /mnt/storage/image:/var/lib/salix/image
|
||||
deploy:
|
||||
replicas: 6
|
||||
replicas: ${BACK_REPLICAS:?}
|
||||
configs:
|
||||
datasources:
|
||||
external: true
|
||||
|
|
|
@ -721,9 +721,9 @@ export default {
|
|||
},
|
||||
workerSummary: {
|
||||
header: 'vn-worker-summary h5',
|
||||
id: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) > section > span',
|
||||
email: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(3) > section > span',
|
||||
department: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(4) > section > span',
|
||||
id: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(3) > section > span',
|
||||
email: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(4) > section > span',
|
||||
department: 'vn-worker-summary vn-one:nth-child(1) > vn-label-value:nth-child(5) > section > span',
|
||||
userId: 'vn-worker-summary vn-one:nth-child(2) > vn-label-value:nth-child(2) > section > span',
|
||||
userName: 'vn-worker-summary vn-one:nth-child(2) > vn-label-value:nth-child(3) > section > span',
|
||||
role: 'vn-worker-summary vn-one:nth-child(2) > vn-label-value:nth-child(4) > section > span',
|
||||
|
|
|
@ -35,14 +35,13 @@ module.exports = Self => {
|
|||
accountConfig
|
||||
} = this;
|
||||
|
||||
let newEntry;
|
||||
let dn = `uid=${userName},${this.userDn}`;
|
||||
|
||||
if (info.hasAccount) {
|
||||
let {user} = info;
|
||||
|
||||
let oldUser = await client.searchOne(this.userDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['userPassword', 'sambaNTPassword'],
|
||||
filter: `&(uid=${userName})`
|
||||
});
|
||||
|
||||
|
@ -52,7 +51,7 @@ module.exports = Self => {
|
|||
? nameArgs.splice(1).join(' ')
|
||||
: '-';
|
||||
|
||||
newEntry = {
|
||||
let newEntry = {
|
||||
uid: userName,
|
||||
objectClass: [
|
||||
'inetOrgPerson',
|
||||
|
@ -101,62 +100,115 @@ module.exports = Self => {
|
|||
if (newEntry[prop] == null)
|
||||
delete newEntry[prop];
|
||||
}
|
||||
|
||||
if (oldUser) {
|
||||
let changes = [];
|
||||
let skipProps = new Set([
|
||||
'dn',
|
||||
'controls'
|
||||
]);
|
||||
|
||||
for (let prop in oldUser) {
|
||||
let deleteProp = !skipProps.has(prop)
|
||||
&& !newEntry.hasOwnProperty(prop);
|
||||
if (!deleteProp) continue;
|
||||
changes.push(new ldap.Change({
|
||||
operation: 'delete',
|
||||
modification: {
|
||||
[prop]: oldUser[prop]
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (let prop in newEntry) {
|
||||
if (this.isEqual(oldUser[prop], newEntry[prop]))
|
||||
continue;
|
||||
changes.push(new ldap.Change({
|
||||
operation: 'replace',
|
||||
modification: {
|
||||
[prop]: newEntry[prop]
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (changes.length)
|
||||
await client.modify(dn, changes);
|
||||
} else
|
||||
await client.add(dn, newEntry);
|
||||
} else {
|
||||
try {
|
||||
await client.del(dn);
|
||||
console.log(` -> User '${userName}' removed from LDAP`);
|
||||
} catch (e) {
|
||||
if (e.name !== 'NoSuchObjectError') throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Remove and recreate (if applicable) user
|
||||
|
||||
let dn = `uid=${userName},${this.userDn}`;
|
||||
let operation;
|
||||
|
||||
try {
|
||||
await client.del(dn);
|
||||
operation = 'delete';
|
||||
} catch (e) {
|
||||
if (e.name !== 'NoSuchObjectError') throw e;
|
||||
}
|
||||
|
||||
if (info.hasAccount) {
|
||||
await client.add(dn, newEntry);
|
||||
operation = 'add';
|
||||
}
|
||||
|
||||
if (operation === 'delete')
|
||||
console.log(` -> User '${userName}' removed from LDAP`);
|
||||
isEqual(a, b) {
|
||||
if (Array.isArray(a) && Array.isArray(b)) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
for (let element of a) {
|
||||
if (b.indexOf(element) === -1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
return a == b;
|
||||
},
|
||||
|
||||
async syncUserGroups(userName, info) {
|
||||
let {client} = this;
|
||||
let {user} = info;
|
||||
let groupDn = this.groupDn;
|
||||
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
attributes: ['dn', 'cn'],
|
||||
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
||||
};
|
||||
let oldGroups = await client.searchAll(this.groupDn, opts);
|
||||
let oldGroups = await client.searchAll(groupDn, opts);
|
||||
|
||||
let reqs = [];
|
||||
for (let oldGroup of oldGroups) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'delete',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
reqs.push(client.modify(oldGroup.dn, change));
|
||||
let deleteGroups = [];
|
||||
let addGroups = [];
|
||||
|
||||
if (info.hasAccount) {
|
||||
let oldSet = new Set();
|
||||
oldGroups.forEach(e => oldSet.add(e.cn));
|
||||
|
||||
let newSet = new Set();
|
||||
user.roles().forEach(e => newSet.add(e.inherits().name));
|
||||
|
||||
for (let group of oldGroups) {
|
||||
if (!newSet.has(group.cn))
|
||||
deleteGroups.push(group.cn);
|
||||
}
|
||||
for (let role of user.roles()) {
|
||||
if (!oldSet.has(role.inherits().name))
|
||||
addGroups.push(role.inherits().name);
|
||||
}
|
||||
} else {
|
||||
for (let group of oldGroups)
|
||||
deleteGroups.push(group.cn);
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
|
||||
if (!info.hasAccount) return;
|
||||
|
||||
reqs = [];
|
||||
for (let role of info.user.roles()) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'add',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
let roleName = role.inherits().name;
|
||||
let dn = `cn=${roleName},${this.groupDn}`;
|
||||
reqs.push(client.modify(dn, change));
|
||||
async function applyOperations(groups, operation) {
|
||||
for (let group of groups) {
|
||||
try {
|
||||
let dn = `cn=${group},${groupDn}`;
|
||||
await client.modify(dn, new ldap.Change({
|
||||
operation,
|
||||
modification: {memberUid: userName}
|
||||
}));
|
||||
} catch (err) {
|
||||
if (err.name !== 'NoSuchObjectError')
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
|
||||
await applyOperations(deleteGroups, 'delete');
|
||||
await applyOperations(addGroups, 'add');
|
||||
},
|
||||
|
||||
async getUsers(usersToSync) {
|
||||
|
|
|
@ -33,7 +33,7 @@ class Controller extends Section {
|
|||
get reportParams() {
|
||||
const userParams = this.$.model.userParams;
|
||||
return Object.assign({
|
||||
authorization: this.vnToken.token,
|
||||
recipient: this.client.email,
|
||||
recipientId: this.client.id
|
||||
}, userParams);
|
||||
}
|
||||
|
|
|
@ -93,7 +93,12 @@ module.exports = Self => {
|
|||
let where = buildFilter(ctx.args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {'e.id': value};
|
||||
return /^\d+$/.test(value)
|
||||
? {'e.id': value}
|
||||
: {or: [
|
||||
{'s.name': {like: `%${value}%`}},
|
||||
{'s.nickname': {like: `%${value}%`}}
|
||||
]};
|
||||
case 'ref':
|
||||
param = `e.${param}`;
|
||||
return {[param]: {like: `%${value}%`}};
|
||||
|
@ -141,6 +146,7 @@ module.exports = Self => {
|
|||
e.invoiceInFk,
|
||||
t.landed,
|
||||
s.name AS supplierName,
|
||||
s.nickname AS supplierAlias,
|
||||
co.code AS companyCode,
|
||||
cu.code AS currencyCode
|
||||
FROM vn.entry e
|
||||
|
|
|
@ -8,11 +8,14 @@
|
|||
<vn-searchbar
|
||||
vn-focus
|
||||
panel="vn-entry-search-panel"
|
||||
info="Search entrys by id"
|
||||
info="Search entry by id or a suppliers by name or alias"
|
||||
model="model">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
||||
<ui-view></ui-view>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
vn-one
|
||||
label="General search"
|
||||
ng-model="filter.search"
|
||||
info="Search entries by id"
|
||||
info="Search entry by id or a suppliers by name or alias"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
@ -45,8 +45,11 @@
|
|||
label="Supplier"
|
||||
ng-model="filter.supplierFk"
|
||||
url="Suppliers"
|
||||
fields="['name','nickname']"
|
||||
search-function="{or: [{nickname: {like: '%'+ $search +'%'}}, {name: {like: '%'+ $search +'%'}}]}"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
<tpl-item>{{name}}: {{nickname}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
|
|
|
@ -4,4 +4,5 @@ Nickname: Alias
|
|||
From: Desde
|
||||
To: Hasta
|
||||
Agency: Agencia
|
||||
Warehouse: Almacén
|
||||
Warehouse: Almacén
|
||||
Search entry by id or a suppliers by name or alias: Buscar entrada por id o proveedores por nombre y alias
|
|
@ -119,6 +119,7 @@ module.exports = Self => {
|
|||
ori.code AS origin,
|
||||
ic.name AS category,
|
||||
i.density,
|
||||
i.stemMultiplier,
|
||||
b.grouping,
|
||||
b.packing,
|
||||
itn.code AS niche, @visibleCalc
|
||||
|
|
|
@ -65,7 +65,10 @@
|
|||
"type": "number",
|
||||
"description": "Density"
|
||||
},
|
||||
"image": {
|
||||
"stemMultiplier": {
|
||||
"type": "number",
|
||||
"description": "Multiplier"
|
||||
},"image": {
|
||||
"type": "string",
|
||||
"description": "Image"
|
||||
},
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<vn-th field="origin" shrink>Origin</vn-th>
|
||||
<vn-th field="salesperson" shrink>Buyer</vn-th>
|
||||
<vn-th field="density" shrink>Density</vn-th>
|
||||
<vn-th field="stemMultiplier" shrink>Multiplier</vn-th>
|
||||
<vn-th field="active" shrink>Active</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
|
@ -78,6 +79,7 @@
|
|||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{::item.density}}</vn-td>
|
||||
<vn-td shrink >{{::item.stemMultiplier}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-check
|
||||
disabled="true"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
vn-id="typesModel"
|
||||
auto-load="true"
|
||||
url="TicketServiceTypes"
|
||||
data="ticketServiceTypes"
|
||||
|
|
|
@ -35,6 +35,10 @@ class Controller extends Section {
|
|||
throw new UserError(`Name can't be empty`);
|
||||
|
||||
return this.$http.post(`TicketServiceTypes`, this.$.newServiceType)
|
||||
.then(res => {
|
||||
this.$.typesModel.refresh();
|
||||
return res;
|
||||
})
|
||||
.then(res => service.ticketServiceTypeFk = res.data.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import './index.js';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Ticket component vnTicketService', () => {
|
||||
let controller;
|
||||
|
@ -11,7 +12,7 @@ describe('Ticket component vnTicketService', () => {
|
|||
beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
|
||||
$scope.typesModel = crudModel;
|
||||
$element = angular.element(`<div></div>`);
|
||||
controller = $componentController('vnTicketService', {$scope, $element});
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Calendar",
|
||||
"base": "Loggable",
|
||||
"base": "VnModel",
|
||||
"log": {
|
||||
"model": "WorkerLog",
|
||||
"relation": "labour"
|
||||
|
|
|
@ -7,4 +7,4 @@ FROM client c
|
|||
JOIN company AS cny
|
||||
JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk
|
||||
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
||||
WHERE c.id = ? AND cny.id = ?`
|
||||
WHERE c.id = ? AND cny.id = ?
|
Loading…
Reference in New Issue