Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2764-Ticket_sale_consignee
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Jorge Padawan 2021-02-12 11:57:54 +01:00
commit 1512a34a73
27 changed files with 355 additions and 80 deletions

View File

@ -35,3 +35,4 @@ rules:
space-in-parens: ["error", "never"] space-in-parens: ["error", "never"]
jasmine/no-focused-tests: 0 jasmine/no-focused-tests: 0
jasmine/prefer-toHaveBeenCalledWith: 0 jasmine/prefer-toHaveBeenCalledWith: 0
arrow-spacing: ["error", { "before": true, "after": true }]

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

@ -151,19 +151,19 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`) INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`)
VALUES VALUES
(1, 'CC y Polizas de crédito', NULL, NULL), (1, 'CC y Polizas de crédito', NULL, NULL),
(2, 'Cash', NULL, 'cash'), (2, 'Cash', 'Cash', 'cash'),
(3, 'Credit card', NULL, 'creditCard'), (3, 'Credit card', 'Credit Card', 'creditCard'),
(4, 'Finalcial lines', NULL, NULL), (4, 'Finalcial lines', NULL, NULL),
(5, 'Other products', NULL, NULL), (5, 'Other products', NULL, NULL),
(6, 'Loans', NULL, NULL), (6, 'Loans', NULL, NULL),
(7, 'Leasing', NULL, NULL), (7, 'Leasing', NULL, NULL),
(8, 'Compensations', 'Compensations', 'Compensations'); (8, 'Compensations', 'Compensations', 'compensation');
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
VALUES VALUES
(1, 'Pay on receipt', '0000000000', 3, 0, 1, 1), (1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
(2, 'Cash', '1111111111', 2, 0, 1, 1), (2, 'Cash', '5700000001', 2, 0, 1, 1),
(3, 'Compensation', '0000000000', 8, 0, 1, 1); (3, 'Compensation', '4000000000', 8, 0, 1, 1);
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`) INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
VALUES VALUES
@ -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

@ -171,5 +171,6 @@
"New ticket request has been created with price": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*", "New ticket request has been created with price": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*",
"New ticket request has been created": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}*", "New ticket request has been created": "Se ha creado una nueva petición de compra *'{{description}}'* para el día *{{shipped}}*, con una cantidad de *{{quantity}}*",
"That item doesn't exists": "Ese artículo no existe", "That item doesn't exists": "Ese artículo no existe",
"There's a new urgent ticket": "Hay un nuevo ticket urgente: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})" "There's a new urgent ticket": "Hay un nuevo ticket urgente: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})",
"Compensation account is empty": "La cuenta para compensar está vacia"
} }

View File

@ -62,7 +62,10 @@ module.exports = function(Self) {
const bank = await models.Bank.findById(args.bankFk); const bank = await models.Bank.findById(args.bankFk);
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk); const accountingType = await models.AccountingType.findById(bank.accountingTypeFk);
if (args.compensationAccount) { if (accountingType.code == 'compensation') {
if (!args.compensationAccount)
throw new UserError('Compensation account is empty');
const supplierCompensation = await models.Supplier.findOne({ const supplierCompensation = await models.Supplier.findOne({
where: { where: {
account: args.compensationAccount account: args.compensationAccount
@ -92,12 +95,11 @@ module.exports = function(Self) {
], ],
options); options);
} else { } else {
const description = `${clientOriginal.id} : ${clientOriginal.nickname} - ${accountingType.receiptDescription}`; const description = `${clientOriginal.id} : ${clientOriginal.socialName} - ${accountingType.receiptDescription}`;
const [xdiarioNew] = await Self.rawSql( const [xdiarioNew] = await Self.rawSql(
`SELECT xdiario_new(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ledger;`, `SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ledger;`,
[ [
null, null,
Date(),
bank.account, bank.account,
clientOriginal.accountingAccount, clientOriginal.accountingAccount,
description, description,
@ -114,10 +116,9 @@ module.exports = function(Self) {
options); options);
await Self.rawSql( await Self.rawSql(
`SELECT xdiario_new(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, `SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`,
[ [
xdiarioNew.ledger, xdiarioNew.ledger,
Date(),
clientOriginal.accountingAccount, clientOriginal.accountingAccount,
bank.account, bank.account,
description, description,

View File

@ -38,6 +38,29 @@ describe('Client createReceipt', () => {
await till.destroy(); await till.destroy();
}); });
it('should throw Compensation account is empty', async() => {
const bankFk = 3;
let ctx = {
args: {
clientFk: clientFk,
payed: payed,
companyFk: companyFk,
bankFk: bankFk,
amountPaid: amountPaid,
description: description
}
};
try {
await app.models.Client.createReceipt(ctx);
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.message).toEqual('Compensation account is empty');
});
it('should throw Invalid account if compensationAccount does not belongs to a client nor a supplier', async() => { it('should throw Invalid account if compensationAccount does not belongs to a client nor a supplier', async() => {
let error; let error;
const bankFk = 3; const bankFk = 3;

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,6 +64,7 @@
<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-class="::{'warning chip': sale.highlighted}">
<span ng-if="::!sale.isTicket"> <span ng-if="::!sale.isTicket">
{{::sale.name | dashIfEmpty}} {{::sale.name | dashIfEmpty}}
</span> </span>
@ -73,6 +74,7 @@
class="link"> class="link">
{{::sale.name | dashIfEmpty}} {{::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>
<vn-td number>{{::sale.out | dashIfEmpty}}</vn-td> <vn-td number>{{::sale.out | dashIfEmpty}}</vn-td>

View File

@ -162,7 +162,7 @@
"acl": ["buyer"] "acl": ["buyer"]
}, },
{ {
"url" : "/fixed-price", "url" : "/fixed-price?q",
"state": "item.fixedPrice", "state": "item.fixedPrice",
"component": "vn-fixed-price", "component": "vn-fixed-price",
"description": "Fixed prices", "description": "Fixed prices",

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

@ -37,7 +37,7 @@ class Controller extends Component {
}; };
filter = encodeURIComponent(JSON.stringify(filter)); filter = encodeURIComponent(JSON.stringify(filter));
let query = `Clients?filter=${filter}`; let query = `Clients?filter=${filter}`;
this.$http.get(query).then(res => { this.$http.get(query).then(res=> {
if (res.data) { if (res.data) {
let client = res.data[0]; let client = res.data[0];
let defaultAddress = client.defaultAddress; let defaultAddress = client.defaultAddress;

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

View File

@ -101,7 +101,7 @@ module.exports = Self => {
if (!shipped && landed) { if (!shipped && landed) {
const shippedResult = await models.Agency.getShipped(landed, const shippedResult = await models.Agency.getShipped(landed,
address.id, agencyModeId, warehouseId); address.id, agencyModeId, warehouseId);
shipped = shippedResult && shippedResult.shipped; shipped = (shippedResult && shippedResult.shipped) || landed;
} }
if (shipped && !landed) { if (shipped && !landed) {

View File

@ -2,12 +2,13 @@ const app = require('vn-loopback/server/server');
let UserError = require('vn-loopback/util/user-error'); let UserError = require('vn-loopback/util/user-error');
describe('ticket new()', () => { describe('ticket new()', () => {
let ticket; let ticketIdsToDelete = [];
let today = new Date(); let today = new Date();
let ctx = {req: {accessToken: {userId: 1}}}; let ctx = {req: {accessToken: {userId: 1}}};
afterAll(async done => { afterAll(async done => {
await app.models.Ticket.destroyById(ticket.id); for (id of ticketIdsToDelete)
await app.models.Ticket.destroyById(id);
done(); done();
}); });
@ -28,7 +29,7 @@ describe('ticket new()', () => {
params.shipped, params.shipped,
params.landed, params.landed,
params.warehouseId, params.warehouseId,
params.companyFk, params.companyId,
params.addressId params.addressId
).catch(e => { ).catch(e => {
error = e; error = e;
@ -53,7 +54,7 @@ describe('ticket new()', () => {
params.shipped, params.shipped,
params.landed, params.landed,
params.warehouseId, params.warehouseId,
params.companyFk, params.companyId,
params.addressId params.addressId
).catch(response => { ).catch(response => {
expect(response.message).toEqual(`This address doesn't exist`); expect(response.message).toEqual(`This address doesn't exist`);
@ -74,17 +75,44 @@ describe('ticket new()', () => {
agencyModeId: 1 agencyModeId: 1
}; };
ticket = await app.models.Ticket.new(ctx, const ticket = await app.models.Ticket.new(ctx,
params.clientId, params.clientId,
params.shipped, params.shipped,
params.landed, params.landed,
params.warehouseId, params.warehouseId,
params.companyFk, params.companyId,
params.addressId, params.addressId,
params.agencyModeId); params.agencyModeId);
let newestTicketIdInFixtures = 21; let newestTicketIdInFixtures = 21;
ticketIdsToDelete.push(ticket.id);
expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures); expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures);
}); });
it('should return the set a shipped when the agency is not especified', async() => {
let params = {
clientId: 104,
landed: today,
shipped: null,
warehouseId: 2,
companyId: 442,
addressId: 4,
agencyModeId: null
};
const ticket = await app.models.Ticket.new(ctx,
params.clientId,
params.shipped,
params.landed,
params.warehouseId,
params.companyId,
params.addressId,
params.agencyModeId);
ticketIdsToDelete.push(ticket.id);
expect(ticket.shipped).toEqual(jasmine.any(Date));
});
}); });

View File

@ -39,7 +39,7 @@
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
disabled="!$ctrl.clientId || !$ctrl.landed || !$ctrl.warehouseId" disabled="!$ctrl.clientId || !$ctrl.landed || !$ctrl.warehouseId"
data="$ctrl._availableAgencies" data="$ctrl.agencies"
label="Agency" label="Agency"
show-field="agencyMode" show-field="agencyMode"
value-field="agencyModeFk" value-field="agencyModeFk"

View File

@ -100,9 +100,12 @@ class Controller extends Component {
ticket.agencyModeFk = null; ticket.agencyModeFk = null;
this.$http.get(`Agencies/getAgenciesWithWarehouse`, {params}).then(res => { this.$http.get(`Agencies/getAgenciesWithWarehouse`, {params}).then(res => {
this._availableAgencies = res.data; this.agencies = res.data;
const defaultAgency = this.agencies.find(agency=> {
this.agencyModeId = this.defaultAddress.agencyModeFk; return agency.agencyModeFk == this.defaultAddress.agencyModeFk;
});
if (defaultAgency)
this.agencyModeId = defaultAgency.agencyModeFk;
}); });
} }
} }