Merge branch 'dev' into 2725-ticket-create-crear-shimpent
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2021-02-10 07:21:29 +00:00
commit dcad6dc8c8
18 changed files with 270 additions and 52 deletions

8
Jenkinsfile vendored
View File

@ -49,7 +49,7 @@ pipeline {
NODE_ENV = "" NODE_ENV = ""
} }
steps { steps {
nodejs('node-lts') { nodejs('node-v12') {
sh 'npm install --no-audit --prefer-offline' sh 'npm install --no-audit --prefer-offline'
sh 'gulp install --ci' sh 'gulp install --ci'
} }
@ -66,14 +66,14 @@ pipeline {
parallel { parallel {
stage('Frontend') { stage('Frontend') {
steps { steps {
nodejs('node-lts') { nodejs('node-v12') {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
} }
} }
} }
// stage('Backend') { // stage('Backend') {
// steps { // steps {
// nodejs('node-lts') { // nodejs('node-v12') {
// sh 'gulp launchBackTest --ci' // sh 'gulp launchBackTest --ci'
// } // }
// } // }
@ -89,7 +89,7 @@ pipeline {
CREDS = credentials('docker-registry') CREDS = credentials('docker-registry')
} }
steps { steps {
nodejs('node-lts') { nodejs('node-v12') {
sh 'gulp build' sh 'gulp build'
} }

View File

@ -38,8 +38,7 @@ module.exports = Self => {
{ {
arg: 'hasFile', arg: 'hasFile',
type: 'Boolean', type: 'Boolean',
description: 'True if has an attached file', description: 'True if has an attached file'
required: true
}, },
{ {
arg: 'hasFileAttached', arg: 'hasFileAttached',

View File

@ -0,0 +1,137 @@
DROP PROCEDURE `vn`.`item_getBalance`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId INT, IN vWarehouse INT)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
SELECT inventoried INTO vDateInventory FROM config;
SET @a = 0;
SET @currentLineFk = 0;
SET @shipped = '';
SELECT DATE(@shipped:= shipped) shipped,
alertLevel,
stateName,
origin,
reference,
clientFk,
name,
`in`,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
@currentLineFk := IF (@shipped < CURDATE()
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
lineFk,@currentLineFk) lastPreparedLineFk,
isTicket,
lineFk,
isPicked,
clientType
FROM
( SELECT tr.landed AS shipped,
b.quantity AS `in`,
NULL AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
s.name AS name,
e.ref AS reference,
e.id AS origin,
s.id AS clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id lineFk,
NULL `order`,
NULL AS clientType
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT tr.shipped,
NULL as `in`,
b.quantity AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
s.name AS name,
e.ref AS reference,
e.id AS origin,
s.id AS clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id,
NULL `order`,
NULL AS clientType
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN warehouse w ON w.id = tr.warehouseOutFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND w.isFeedStock = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT DATE(t.shipped),
NULL as `in`,
s.quantity AS `out`,
al.alertLevel AS alertLevel,
st.name AS stateName,
t.nickname AS name,
t.refFk AS reference,
t.id AS origin,
t.clientFk,
stk.id AS isPicked,
TRUE AS isTicket,
s.id,
st.`order`,
ct.code AS clientType
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN ticketState ts ON ts.ticket = t.id
LEFT JOIN state st ON st.code = ts.code
JOIN client c ON c.id = t.clientFk
JOIN clientType ct ON ct.id = c.clientTypeFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN t.shipped < curdate() THEN 3
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
) AS itemDiary;
END$$
DELIMITER ;

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`supplier` ADD COLUMN `workerFk` INT(11) NULL DEFAULT NULL COMMENT 'Responsible for approving invoices' AFTER `isTrucker`;
ALTER TABLE `vn`.`supplier` ADD CONSTRAINT `supplier_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE;

View File

@ -1233,11 +1233,11 @@ INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`)
(104, 500), (104, 500),
(105, 5000); (105, 5000);
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`) INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`)
VALUES VALUES
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1), (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18),
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8), (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18),
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3); (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18);
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
VALUES VALUES

View File

@ -316,7 +316,7 @@ export default {
fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]', fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]',
fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]', fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]',
fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]', fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]',
fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-textfield[ng-model="itemTag.value"]', fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-autocomplete[ng-model="itemTag.value"]',
fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]', fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]',
sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]', sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]',
sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]', sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]',

View File

@ -16,7 +16,7 @@ describe('Item create tags path', () => {
await browser.close(); await browser.close();
}); });
it(`should create a new tag and delete a former one`, async() => { it('should create a new tag and delete a former one', async() => {
await page.waitToClick(selectors.itemTags.fourthRemoveTagButton); await page.waitToClick(selectors.itemTags.fourthRemoveTagButton);
await page.waitToClick(selectors.itemTags.addItemTagButton); await page.waitToClick(selectors.itemTags.addItemTagButton);
await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base'); await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base');
@ -29,7 +29,7 @@ describe('Item create tags path', () => {
expect(message.text).toContain('Data saved!'); expect(message.text).toContain('Data saved!');
}); });
it(`should confirm the fourth row data is the expected one`, async() => { it('should confirm the fourth row data is the expected one', async() => {
await page.reloadSection('item.card.tags'); await page.reloadSection('item.card.tags');
await page.waitForSelector('vn-item-tags'); await page.waitForSelector('vn-item-tags');
let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value'); let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value');
@ -47,7 +47,7 @@ describe('Item create tags path', () => {
expect(result).toEqual('4'); expect(result).toEqual('4');
}); });
it(`should confirm the fifth row data is the expected one`, async() => { it('should confirm the fifth row data is the expected one', async() => {
let tag = await page let tag = await page
.waitToGetProperty(selectors.itemTags.fifthTag, 'value'); .waitToGetProperty(selectors.itemTags.fifthTag, 'value');
@ -62,7 +62,7 @@ describe('Item create tags path', () => {
expect(relevancy).toEqual('5'); expect(relevancy).toEqual('5');
}); });
it(`should confirm the sixth row data is the expected one`, async() => { it('should confirm the sixth row data is the expected one', async() => {
let tag = await page let tag = await page
.waitToGetProperty(selectors.itemTags.sixthTag, 'value'); .waitToGetProperty(selectors.itemTags.sixthTag, 'value');

View File

@ -20,8 +20,12 @@ module.exports = Self => {
}); });
Self.getBalance = async filter => { Self.getBalance = async filter => {
let where = filter.where; const where = filter.where;
let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]); let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]);
for (const entry of diary)
if (entry.clientType === 'loses') entry.highlighted = true;
return diary; return diary;
}; };
}; };

View File

@ -0,0 +1,33 @@
const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('item getBalance()', () => {
it('should return the balance lines of a client type loses in which one has highlighted true', async() => {
const activeCtx = {
accessToken: {userId: 9},
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
const losesClientId = 111;
const ticket = await app.models.Ticket.findById(7);
const originalClientId = ticket.clientFk;
await ticket.updateAttribute('clientFk', losesClientId);
const filter = {
where: {
itemFk: 1,
warehouseFk: 1
}
};
const results = await app.models.Item.getBalance(filter);
const result = results.find(element => element.clientType == 'loses');
expect(result.highlighted).toBe(true);
// restores
await ticket.updateAttribute('clientFk', originalClientId);
});
});

View File

@ -64,14 +64,16 @@
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td> <vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td> <vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
<vn-td class="truncate" expand> <vn-td class="truncate" expand>
<span ng-if="::!sale.isTicket"> <span ng-class="::{'warning chip': sale.highlighted}">
{{::sale.name | dashIfEmpty}} <span ng-if="::!sale.isTicket">
</span> {{::sale.name | dashIfEmpty}}
<span </span>
ng-if="::sale.isTicket" <span
vn-click-stop="clientDescriptor.show($event, sale.clientFk)" ng-if="::sale.isTicket"
class="link"> vn-click-stop="clientDescriptor.show($event, sale.clientFk)"
{{::sale.name | dashIfEmpty}} class="link">
{{::sale.name | dashIfEmpty}}
</span>
</span> </span>
</vn-td> </vn-td>
<vn-td number class="in">{{::sale.in | dashIfEmpty}}</vn-td> <vn-td number class="in">{{::sale.in | dashIfEmpty}}</vn-td>

View File

@ -32,14 +32,14 @@
rule> rule>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield vn-three <vn-textfield vn-three
ng-show="tag.selection.isFree || tag.selection.isFree == undefined" ng-if="tag.selection.isFree || tag.selection.isFree == undefined"
vn-id="text" vn-id="text"
label="Value" label="Value"
ng-model="itemTag.value" ng-model="itemTag.value"
rule> rule>
</vn-textfield> </vn-textfield>
<vn-autocomplete vn-three <vn-autocomplete vn-three
ng-show="tag.selection.isFree === false" ng-if="tag.selection.isFree === false"
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}" url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
search-function="{value: $search}" search-function="{value: $search}"
label="Value" label="Value"

View File

@ -42,6 +42,7 @@ module.exports = Self => {
'sageTaxTypeFk', 'sageTaxTypeFk',
'sageTransactionTypeFk', 'sageTransactionTypeFk',
'sageWithholdingFk', 'sageWithholdingFk',
'workerFk'
], ],
include: [ include: [
{ {
@ -85,7 +86,19 @@ module.exports = Self => {
scope: { scope: {
fields: ['id', 'withholding'] fields: ['id', 'withholding']
} }
} },
{
relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}
},
] ]
}; };
let supplier = await Self.app.models.Supplier.findOne(filter); let supplier = await Self.app.models.Supplier.findOne(filter);

View File

@ -11,75 +11,78 @@
}, },
"properties": { "properties": {
"id": { "id": {
"type": "Number", "type": "number",
"id": true, "id": true,
"description": "Identifier" "description": "Identifier"
}, },
"name": { "name": {
"type": "String" "type": "string"
}, },
"account": { "account": {
"type": "String" "type": "string"
}, },
"countryFk": { "countryFk": {
"type": "Number" "type": "number"
}, },
"nif": { "nif": {
"type": "String" "type": "string"
}, },
"isFarmer": { "isFarmer": {
"type": "Boolean" "type": "boolean"
}, },
"phone": { "phone": {
"type": "Number" "type": "number"
}, },
"retAccount": { "retAccount": {
"type": "Number" "type": "number"
}, },
"commission": { "commission": {
"type": "Boolean" "type": "boolean"
}, },
"created": { "created": {
"type": "Date" "type": "date"
}, },
"postcodeFk": { "postcodeFk": {
"type": "Number" "type": "number"
}, },
"isActive": { "isActive": {
"type": "Boolean" "type": "boolean"
}, },
"isOfficial": { "isOfficial": {
"type": "Boolean" "type": "boolean"
}, },
"isSerious": { "isSerious": {
"type": "Boolean" "type": "boolean"
}, },
"note": { "note": {
"type": "String" "type": "string"
}, },
"street": { "street": {
"type": "String" "type": "string"
}, },
"city": { "city": {
"type": "String" "type": "string"
}, },
"provinceFk": { "provinceFk": {
"type": "Number" "type": "number"
}, },
"postCode": { "postCode": {
"type": "String" "type": "string"
}, },
"payMethodFk": { "payMethodFk": {
"type": "Number" "type": "number"
}, },
"payDemFk": { "payDemFk": {
"type": "Number" "type": "number"
}, },
"payDay": { "payDay": {
"type": "Number" "type": "number"
}, },
"nickname": { "nickname": {
"type": "String" "type": "string"
},
"workerFk": {
"type": "number"
}, },
"sageTaxTypeFk": { "sageTaxTypeFk": {
"type": "number", "type": "number",
@ -126,6 +129,11 @@
"model": "Client", "model": "Client",
"foreignKey": "nif", "foreignKey": "nif",
"primaryKey": "fi" "primaryKey": "fi"
},
"worker": {
"type": "belongsTo",
"model": "Worker",
"foreignKey": "workerFk"
}, },
"sageTaxType": { "sageTaxType": {
"type": "belongsTo", "type": "belongsTo",

View File

@ -15,6 +15,17 @@
rule rule
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
<vn-autocomplete
vn-one
ng-model="$ctrl.supplier.workerFk"
url="Clients/activeWorkersWithRole"
search-function="{firstName: $search}"
show-field="nickname"
value-field="id"
where="{role: 'employee'}"
label="Responsible"
info="Responsible for approving invoices">
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-check <vn-check

View File

@ -1,3 +1,4 @@
Notes: Notas Notes: Notas
Active: Activo Active: Activo
Verified: Verificado Verified: Verificado
Responsible for approving invoices: Responsable de aprobar las facturas

View File

@ -31,6 +31,13 @@
label="Alias" label="Alias"
value="{{::$ctrl.summary.nickname}}"> value="{{::$ctrl.summary.nickname}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Responsible">
<span
ng-click="workerDescriptor.show($event, $ctrl.summary.workerFk)"
class="link">
{{$ctrl.summary.worker.user.nickname}}
</span>
</vn-label-value>
<vn-label-value no-ellipsize <vn-label-value no-ellipsize
label="Notes" label="Notes"
value="{{::$ctrl.summary.note}}"> value="{{::$ctrl.summary.note}}">

View File

@ -7,3 +7,4 @@ Sage tax type: Tipo de impuesto Sage
Sage transaction type: Tipo de transacción Sage Sage transaction type: Tipo de transacción Sage
Sage withholding: Retencion Sage Sage withholding: Retencion Sage
Go to the supplier: Ir al proveedor Go to the supplier: Ir al proveedor
Responsible: Responsable