Merge branch 'dev' into 7006-itemTypeLog
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Guillermo Bonet 2024-10-25 11:06:55 +00:00
commit 956e89475e
140 changed files with 1986 additions and 1308 deletions

View File

@ -32,8 +32,7 @@ RUN apt-get update \
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
samba-common-bin samba-dsdb-modules\ samba-common-bin samba-dsdb-modules\
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/*
&& npm -g install pm2
# Salix # Salix
@ -55,7 +54,4 @@ COPY \
README.md \ README.md \
./ ./
CMD ["pm2-runtime", "./back/process.yml"] CMD ["node", "--tls-min-v1.0", "--openssl-legacy-provider", "./loopback/server/server.js"]
HEALTHCHECK --interval=15s --timeout=10s \
CMD curl -f http://localhost:3000/api/Applications/status || exit 1

View File

@ -19,8 +19,15 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
const [info, info2, [{'@vCollectionFk': collectionFk}]] = await Self.rawSql(
'CALL vn.collection_getAssigned(?, @vCollectionFk);SELECT @vCollectionFk', [userId], myOptions); const randStr = Math.random().toString(36).substring(3);
const result = await Self.rawSql(`
CALL vn.collection_getAssigned(?, @vCollectionFk);
SELECT @vCollectionFk ?
`, [userId, randStr], myOptions);
const collectionFk = result.find(item => item[0]?.[randStr] !== undefined)?.[0]?.[randStr];
if (!collectionFk) throw new UserError('There are not picking tickets'); if (!collectionFk) throw new UserError('There are not picking tickets');
await Self.rawSql('CALL vn.collection_printSticker(?, NULL)', [collectionFk], myOptions); await Self.rawSql('CALL vn.collection_printSticker(?, NULL)', [collectionFk], myOptions);

View File

@ -62,7 +62,8 @@ module.exports = Self => {
p.code parkingCodePrevia, p.code parkingCodePrevia,
p.pickingOrder pickingOrderPrevia, p.pickingOrder pickingOrderPrevia,
iss.id itemShelvingSaleFk, iss.id itemShelvingSaleFk,
iss.isPicked iss.isPicked,
iss.itemShelvingFk
FROM ticketCollection tc FROM ticketCollection tc
LEFT JOIN collection c ON c.id = tc.collectionFk LEFT JOIN collection c ON c.id = tc.collectionFk
JOIN sale s ON s.ticketFk = tc.ticketFk JOIN sale s ON s.ticketFk = tc.ticketFk
@ -102,7 +103,8 @@ module.exports = Self => {
p.code, p.code,
p.pickingOrder, p.pickingOrder,
iss.id itemShelvingSaleFk, iss.id itemShelvingSaleFk,
iss.isPicked iss.isPicked,
iss.itemShelvingFk
FROM sectorCollection sc FROM sectorCollection sc
JOIN sectorCollectionSaleGroup ss ON ss.sectorCollectionFk = sc.id JOIN sectorCollectionSaleGroup ss ON ss.sectorCollectionFk = sc.id
JOIN saleGroup sg ON sg.id = ss.saleGroupFk JOIN saleGroup sg ON sg.id = ss.saleGroupFk

View File

@ -4,21 +4,45 @@ module.exports = Self => {
/** /**
* Returns basic headers * Returns basic headers
* *
* @param {string} cookie - The docuware cookie
* @return {object} - The headers * @return {object} - The headers
*/ */
Self.getOptions = async() => { Self.getOptions = async() => {
const docuwareConfig = await Self.app.models.DocuwareConfig.findOne(); const docuwareConfig = await Self.app.models.DocuwareConfig.findOne();
const now = Date.vnNow();
let {url, username, password, token, expired} = docuwareConfig;
if (process.env.NODE_ENV && (!expired || expired < now + 60)) {
const {data: {IdentityServiceUrl}} = await axios.get(`${url}/Home/IdentityServiceInfo`);
const {data: {token_endpoint}} = await axios.get(`${IdentityServiceUrl}/.well-known/openid-configuration`);
const {data} = await axios.post(token_endpoint, {
grant_type: 'password',
scope: 'docuware.platform',
client_id: 'docuware.platform.net.client',
username,
password
}, {headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}});
const newToken = data.access_token;
token = data.token_type + ' ' + newToken;
await docuwareConfig.updateAttributes({
token,
expired: now + data.expires_in
});
}
const headers = { const headers = {
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Cookie': docuwareConfig.cookie 'Authorization': token
} }
}; };
return { return {
url: docuwareConfig.url, url,
headers headers
}; };
}; };

View File

@ -2,87 +2,54 @@ const axios = require('axios');
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
describe('Docuware core', () => { describe('Docuware core', () => {
beforeAll(() => { const fileCabinetCode = 'deliveryNote';
beforeAll(async() => {
process.env.NODE_ENV = 'testing'; process.env.NODE_ENV = 'testing';
});
afterAll(() => { const docuwareInfo = await models.Docuware.findOne({
delete process.env.NODE_ENV; where: {
}); code: fileCabinetCode
}
describe('getOptions()', () => {
it('should return url and headers', async() => {
const result = await models.Docuware.getOptions();
expect(result.url).toBeDefined();
expect(result.headers).toBeDefined();
}); });
});
describe('getDialog()', () => { spyOn(axios, 'get').and.callFake(url => {
it('should return dialogId', async() => { if (url.includes('IdentityServiceInfo')) return {data: {IdentityServiceUrl: 'IdentityServiceUrl'}};
const dialogs = { if (url.includes('IdentityServiceUrl')) return {data: {token_endpoint: 'token_endpoint'}};
data: { if (url.includes('dialogs')) {
Dialog: [ return {
{ data: {
DisplayName: 'find', Dialog: [
Id: 'getDialogTest' {
} DisplayName: 'find',
] Id: 'getDialogTest'
} }
}; ]
spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(dialogs))); }
const result = await models.Docuware.getDialog('deliveryNote', 'find', 'randomFileCabinetId'); };
}
expect(result).toEqual('getDialogTest'); if (url.includes('FileCabinets')) {
}); return {data: {
});
describe('getFileCabinet()', () => {
it('should return fileCabinetId', async() => {
const code = 'deliveryNote';
const docuwareInfo = await models.Docuware.findOne({
where: {
code
}
});
const dialogs = {
data: {
FileCabinet: [ FileCabinet: [
{ {
Name: docuwareInfo.fileCabinetName, Name: docuwareInfo.fileCabinetName,
Id: 'getFileCabinetTest' Id: 'getFileCabinetTest'
} }
] ]
} }};
}; }
spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(dialogs)));
const result = await models.Docuware.getFileCabinet(code);
expect(result).toEqual('getFileCabinetTest');
});
});
describe('get()', () => {
it('should return data without parse', async() => {
spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random()))));
spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random()))));
const data = {
data: {
id: 1
}
};
spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data)));
const result = await models.Docuware.get('deliveryNote');
expect(result.id).toEqual(1);
}); });
it('should return data with parse', async() => { spyOn(axios, 'post').and.callFake(url => {
spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random())))); if (url.includes('token_endpoint')) {
spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random())))); return {data: {
const data = { access_token: 'access_token',
data: { token_type: 'bearer',
expires_in: 10000
}};
}
if (url.includes('DialogExpression')) {
return {data: {
Items: [{ Items: [{
Fields: [ Fields: [
{ {
@ -103,12 +70,52 @@ describe('Docuware core', () => {
] ]
}] }]
} }
}; };
}
});
});
afterAll(() => {
delete process.env.NODE_ENV;
});
describe('getOptions()', () => {
it('should return url and headers', async() => {
const result = await models.Docuware.getOptions();
expect(result.url).toBeDefined();
expect(result.headers).toBeDefined();
});
});
describe('Dialog()', () => {
it('should return dialogId', async() => {
const result = await models.Docuware.getDialog('deliveryNote', 'find', 'randomFileCabinetId');
expect(result).toEqual('getDialogTest');
});
});
describe('getFileCabinet()', () => {
it('should return fileCabinetId', async() => {
const result = await models.Docuware.getFileCabinet(fileCabinetCode);
expect(result).toEqual('getFileCabinetTest');
});
});
describe('get()', () => {
it('should return data without parse', async() => {
const [result] = await models.Docuware.get('deliveryNote');
expect(result.firstRequiredField).toEqual(1);
});
it('should return data with parse', async() => {
const parse = { const parse = {
'firstRequiredField': 'id', 'firstRequiredField': 'id',
'secondRequiredField': 'name', 'secondRequiredField': 'name',
}; };
spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data)));
const [result] = await models.Docuware.get('deliveryNote', null, parse); const [result] = await models.Docuware.get('deliveryNote', null, parse);
expect(result.id).toEqual(1); expect(result.id).toEqual(1);
@ -119,17 +126,14 @@ describe('Docuware core', () => {
describe('getById()', () => { describe('getById()', () => {
it('should return data', async() => { it('should return data', async() => {
spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random())))); spyOn(models.Docuware, 'get');
spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random())))); await models.Docuware.getById('deliveryNote', 1);
const data = {
data: {
id: 1
}
};
spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data)));
const result = await models.Docuware.getById('deliveryNote', 1);
expect(result.id).toEqual(1); expect(models.Docuware.get).toHaveBeenCalledWith(
'deliveryNote',
{condition: [Object({DBName: 'N__ALBAR_N', Value: [1]})]},
undefined
);
}); });
}); });
}); });

View File

@ -143,7 +143,7 @@ module.exports = Self => {
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
'X-File-ModifiedDate': Date.vnNew(), 'X-File-ModifiedDate': Date.vnNew(),
'Cookie': docuwareOptions.headers.headers.Cookie, 'Authorization': docuwareOptions.headers.headers.Authorization,
...data.getHeaders() ...data.getHeaders()
}, },
}; };

View File

@ -1,132 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('machineWorker updateInTime()', () => {
const itBoss = 104;
const davidCharles = 1106;
beforeAll(async() => {
ctx = {
req: {
accessToken: {},
headers: {origin: 'http://localhost'},
__: value => value
}
};
});
it('should throw an error if the plate does not exist', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
const plate = 'RE-123';
ctx.req.accessToken.userId = 1106;
try {
await models.MachineWorker.updateInTime(ctx, plate, options);
await tx.rollback();
} catch (e) {
const error = e;
expect(error.message).toContain('the plate does not exist');
await tx.rollback();
}
});
it('should grab a machine where is not in use', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
const plate = 'RE-003';
ctx.req.accessToken.userId = 1107;
try {
const totalBefore = await models.MachineWorker.find(null, options);
await models.MachineWorker.updateInTime(ctx, plate, options);
const totalAfter = await models.MachineWorker.find(null, options);
expect(totalAfter.length).toEqual(totalBefore.length + 1);
await tx.rollback();
} catch (e) {
await tx.rollback();
}
});
describe('less than 12h', () => {
const plate = 'RE-001';
it('should trow an error if it is not himself', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
ctx.req.accessToken.userId = davidCharles;
try {
await models.MachineWorker.updateInTime(ctx, plate, options);
await tx.rollback();
} catch (e) {
const error = e;
expect(error.message).toContain('This machine is already in use');
await tx.rollback();
}
});
it('should throw an error if it is himself with a different machine', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
ctx.req.accessToken.userId = itBoss;
const plate = 'RE-003';
try {
await models.MachineWorker.updateInTime(ctx, plate, options);
await tx.rollback();
} catch (e) {
const error = e;
expect(error.message).toEqual('You are already using a machine');
await tx.rollback();
}
});
it('should set the out time if it is himself', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
ctx.req.accessToken.userId = itBoss;
try {
const isNotParked = await models.MachineWorker.findOne({
where: {workerFk: itBoss}
}, options);
await models.MachineWorker.updateInTime(ctx, plate, options);
const isParked = await models.MachineWorker.findOne({
where: {workerFk: itBoss}
}, options);
expect(isNotParked.outTime).toBeNull();
expect(isParked.outTime).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
}
});
});
describe('equal or more than 12h', () => {
const plate = 'RE-002';
it('should set the out time and grab the machine', async() => {
const tx = await models.MachineWorker.beginTransaction({});
const options = {transaction: tx};
ctx.req.accessToken.userId = davidCharles;
const filter = {
where: {workerFk: davidCharles, machineFk: 2}
};
try {
const isNotParked = await models.MachineWorker.findOne(filter, options);
const totalBefore = await models.MachineWorker.find(null, options);
await models.MachineWorker.updateInTime(ctx, plate, options);
const isParked = await models.MachineWorker.findOne(filter, options);
const totalAfter = await models.MachineWorker.find(null, options);
expect(isNotParked.outTime).toBeNull();
expect(isParked.outTime).toBeDefined();
expect(totalAfter.length).toEqual(totalBefore.length + 1);
await tx.rollback();
} catch (e) {
await tx.rollback();
}
});
});
});

View File

@ -1,77 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('updateInTime', {
description: 'Updates the corresponding registry if the worker has been registered in the last few hours',
accessType: 'WRITE',
accepts: [
{
arg: 'plate',
type: 'string',
}
],
http: {
path: `/updateInTime`,
verb: 'POST'
}
});
Self.updateInTime = async(ctx, plate, options) => {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const $t = ctx.req.__;
let tx;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const machine = await models.Machine.findOne({
fields: ['id', 'plate'],
where: {plate}
}, myOptions);
if (!machine)
throw new UserError($t('the plate does not exist', {plate}));
const machineWorker = await Self.findOne({
where: {
or: [{machineFk: machine.id}, {workerFk: userId}],
outTime: null,
}
}, myOptions);
const {maxHours} = await models.MachineWorkerConfig.findOne({fields: ['maxHours']}, myOptions);
const hoursDifference = (Date.vnNow() - machineWorker?.inTime?.getTime() ?? 0) / (60 * 60 * 1000);
if (machineWorker) {
const isHimself = userId == machineWorker.workerFk;
const isSameMachine = machine.id == machineWorker.machineFk;
if (hoursDifference < maxHours && !isHimself)
throw new UserError($t('This machine is already in use.'));
if (hoursDifference < maxHours && isHimself && !isSameMachine)
throw new UserError($t('You are already using a machine'));
await machineWorker.updateAttributes({
outTime: Date.vnNew()
}, myOptions);
}
if (!machineWorker || hoursDifference >= maxHours)
await models.MachineWorker.create({machineFk: machine.id, workerFk: userId}, myOptions);
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -72,9 +72,9 @@ describe('Renew Token', () => {
} }
expect(error).toBeDefined(); expect(error).toBeDefined();
const query = 'SELECT * FROM util.debug';
const debugLog = await models.Application.rawSql(query, null); const query = 'SELECT * FROM util.debug WHERE variable = "renewToken"';
const debugLog = await models.Application.rawSql(query);
expect(debugLog.length).toEqual(1); expect(debugLog.length).toEqual(1);
}); });

View File

@ -88,12 +88,6 @@
"Machine": { "Machine": {
"dataSource": "vn" "dataSource": "vn"
}, },
"MachineWorker": {
"dataSource": "vn"
},
"MachineWorkerConfig": {
"dataSource": "vn"
},
"MobileAppVersionControl": { "MobileAppVersionControl": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -16,6 +16,10 @@
"name": { "name": {
"type": "string", "type": "string",
"required": true "required": true
},
"hasDailyInvoice": {
"type": "boolean",
"description": "Indicates if the autonomy has daily invoice enabled"
} }
}, },
"relations": { "relations": {
@ -40,4 +44,4 @@
"permission": "ALLOW" "permission": "ALLOW"
} }
] ]
} }

View File

@ -28,6 +28,10 @@
}, },
"continentFk": { "continentFk": {
"type": "number" "type": "number"
},
"hasDailyInvoice": {
"type": "boolean",
"description": "Indicates if the autonomy has daily invoice enabled"
} }
}, },
"relations": { "relations": {

View File

@ -16,17 +16,17 @@
"url": { "url": {
"type": "string" "type": "string"
}, },
"cookie": { "token": {
"type": "string" "type": "string"
},
"username": {
"type": "string"
},
"password": {
"type": "string"
},
"expired":{
"type": "number"
} }
}, }
"acls": [
{
"property": "*",
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
} }

View File

@ -1,18 +0,0 @@
{
"name": "MachineWorkerConfig",
"base": "VnModel",
"options": {
"mysql": {
"table": "vn.machineWorkerConfig"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"maxHours": {
"type": "number"
}
}
}

View File

@ -1,3 +0,0 @@
module.exports = Self => {
require('../methods/machine-worker/updateInTime')(Self);
};

View File

@ -1,33 +0,0 @@
{
"name": "MachineWorker",
"base": "VnModel",
"options": {
"mysql": {
"table": "vn.machineWorker"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"workerFk": {
"type": "number"
},
"machineFk": {
"type": "number"
},
"inTime": {
"type": "date",
"mysql": {
"columnName": "inTimed"
}
},
"outTime": {
"type": "date",
"mysql": {
"columnName": "outTimed"
}
}
}
}

View File

@ -16,6 +16,9 @@
"name": { "name": {
"type": "string", "type": "string",
"required": true "required": true
},
"autonomyFk": {
"type": "number"
} }
}, },
"relations": { "relations": {
@ -55,4 +58,4 @@
"permission": "ALLOW" "permission": "ALLOW"
} }
] ]
} }

View File

@ -1,7 +0,0 @@
apps:
- script: ./loopback/server/server.js
name: salix-back
instances: 1
max_restarts: 0
autorestart: false
node_args: --tls-min-v1.0 --openssl-legacy-provider

View File

@ -1723,7 +1723,6 @@ INSERT INTO `ACL` VALUES (378,'OsTicket','osTicketReportEmail','WRITE','ALLOW','
INSERT INTO `ACL` VALUES (379,'Item','buyerWasteEmail','WRITE','ALLOW','ROLE','system',NULL); INSERT INTO `ACL` VALUES (379,'Item','buyerWasteEmail','WRITE','ALLOW','ROLE','system',NULL);
INSERT INTO `ACL` VALUES (380,'Claim','claimPickupPdf','READ','ALLOW','ROLE','employee',NULL); INSERT INTO `ACL` VALUES (380,'Claim','claimPickupPdf','READ','ALLOW','ROLE','employee',NULL);
INSERT INTO `ACL` VALUES (381,'Claim','claimPickupEmail','WRITE','ALLOW','ROLE','claimManager',NULL); INSERT INTO `ACL` VALUES (381,'Claim','claimPickupEmail','WRITE','ALLOW','ROLE','claimManager',NULL);
INSERT INTO `ACL` VALUES (382,'Item','labelPdf','READ','ALLOW','ROLE','employee',NULL);
INSERT INTO `ACL` VALUES (383,'Sector','*','READ','ALLOW','ROLE','employee',NULL); INSERT INTO `ACL` VALUES (383,'Sector','*','READ','ALLOW','ROLE','employee',NULL);
INSERT INTO `ACL` VALUES (384,'Sector','*','WRITE','ALLOW','ROLE','employee',NULL); INSERT INTO `ACL` VALUES (384,'Sector','*','WRITE','ALLOW','ROLE','employee',NULL);
INSERT INTO `ACL` VALUES (385,'Route','driverRoutePdf','READ','ALLOW','ROLE','employee',NULL); INSERT INTO `ACL` VALUES (385,'Route','driverRoutePdf','READ','ALLOW','ROLE','employee',NULL);

View File

@ -388,23 +388,23 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
(4, 'GCN Channel'), (4, 'GCN Channel'),
(5, 'The Newspaper'); (5, 'The Newspaper');
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`businessTypeFk`,`typeFk`) INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`businessTypeFk`,`typeFk`)
VALUES VALUES
(1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'),
(1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'),
(1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), (1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'),
(1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), (1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'),
(1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 18, 0, 'florist','normal'), (1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 18, 0, 'florist','normal'),
(1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 19, 0, 'florist','normal'), (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 19, 0, 'florist','normal'),
(1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 19, 0, 'florist','normal'), (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 19, 0, 'florist','normal'),
(1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 5, 1, 300, 13, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 19, 0, 'florist','normal'), (1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 5, 1, 300, 13, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 19, 0, 'florist','normal'),
(1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 9, 0, 'florist','normal'), (1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 9, 0, 'florist','normal'),
(1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, NULL, 1, 'florist','normal'), (1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, NULL, 1, 'florist','normal'),
(1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'), (1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'),
(1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'); (1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses');
INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`)
SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), UPPER(CONCAT(name, 'Social')), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, util.VN_CURDATE(), 1 SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), UPPER(CONCAT(name, 'Social')), CONCAT(name, 'Contact'), UPPER(CONCAT(name, 'Street')), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1
FROM `account`.`role` `r` FROM `account`.`role` `r`
WHERE `r`.`hasLogin` = 1; WHERE `r`.`hasLogin` = 1;
@ -546,7 +546,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
(6, 'Weight', 'weight'), (6, 'Weight', 'weight'),
(7, 'InvoiceOut', 'invoiceOut'), (7, 'InvoiceOut', 'invoiceOut'),
(8, 'DropOff', 'dropOff'), (8, 'DropOff', 'dropOff'),
(9, 'Sustitución', 'substitution'); (9, 'Sustitución', 'substitution'),
(10, 'Finance', 'finance');
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`) INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
VALUES VALUES
@ -631,14 +632,21 @@ INSERT INTO vn.invoiceOutConfig
SET id = 1, SET id = 1,
parallelism = 8; parallelism = 8;
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`) INSERT INTO `vn`.`invoiceOutSerial`
(`code`,`description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
VALUES VALUES
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'), ('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'), ('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'),
('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'), ('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'),
('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'multiple'), ('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'multiple'),
('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL), ('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL),
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'); ('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'),
('H', 'Intracomunitaria rápida', 0, 'CEE', 1, 'quick'),
('P', 'Factura simplificada', 1, 'NATIONAL', 0, NULL),
('PE', 'COOPERATIE FLORAHOLLAND UA', 0, 'CEE', 1, NULL),
('S', 'Simplificada', 1, 'NATIONAL', 0, NULL),
('X', 'Exportación global', 0, 'WORLD', 0, 'global'),
('N', 'Múltiple Intracomunitaria', 0, 'CEE', 1, 'multiple');
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`) INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
VALUES VALUES
@ -2834,12 +2842,6 @@ INSERT INTO `vn`.`machine` (`plate`, `maker`, `model`, `warehouseFk`, `departmen
('RE-001', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442), ('RE-001', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442),
('RE-002', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442); ('RE-002', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442);
INSERT INTO `vn`.`machineWorker` (`workerFk`, `machineFk`, `inTimed`, `outTimed`)
VALUES
(1106, 1, util.VN_CURDATE(), util.VN_CURDATE()),
(1106, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 DAY)),
(1106, 2, util.VN_CURDATE(), NULL),
(1106, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 DAY));
INSERT INTO `vn`.`zoneExclusion` (`id`, `zoneFk`, `dated`, `created`, `userFk`) INSERT INTO `vn`.`zoneExclusion` (`id`, `zoneFk`, `dated`, `created`, `userFk`)
VALUES VALUES
@ -2910,7 +2912,8 @@ INSERT INTO `util`.`notification` (`id`, `name`, `description`)
(6, 'book-entry-deleted', 'accounting entries deleted'), (6, 'book-entry-deleted', 'accounting entries deleted'),
(7, 'zone-included','An email to notify zoneCollisions'), (7, 'zone-included','An email to notify zoneCollisions'),
(8, 'backup-printer-selected','A backup printer has been selected'), (8, 'backup-printer-selected','A backup printer has been selected'),
(9, 'mrw-deadline','The MRW deadline has passed'); (9, 'mrw-deadline','The MRW deadline has passed'),
(10,'invoice-ticket-closure','Tickets not invoiced during the nightly closure ticket process');
TRUNCATE `util`.`notificationAcl`; TRUNCATE `util`.`notificationAcl`;
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`) INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
@ -3822,8 +3825,6 @@ UPDATE vn.collection
UPDATE vn.sale UPDATE vn.sale
SET isPicked =FALSE; SET isPicked =FALSE;
INSERT INTO vn.machineWorkerConfig(id, maxHours)
VALUES(1, 12);
INSERT INTO vn.workerAppTester(workerFk) VALUES(66); INSERT INTO vn.workerAppTester(workerFk) VALUES(66);
@ -3831,9 +3832,6 @@ INSERT INTO `vn`.`machine` (`plate`, `maker`, `model`, `warehouseFk`, `departmen
VALUES VALUES
('RE-003', 'IRON', 'JPH-24', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442); ('RE-003', 'IRON', 'JPH-24', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442);
INSERT INTO vn.machineWorker(workerFk,machineFk,inTimed) VALUES (104,1,'2001-01-01 10:00:00.00.000');
UPDATE vn.buy SET itemOriginalFk = 1 WHERE id = 1; UPDATE vn.buy SET itemOriginalFk = 1 WHERE id = 1;
UPDATE vn.saleTracking SET stateFk = 26 WHERE id = 5; UPDATE vn.saleTracking SET stateFk = 26 WHERE id = 5;
@ -3942,9 +3940,9 @@ INSERT INTO vn.medicalReview
(id, workerFk, centerFk, `date`, `time`, isFit, amount, invoice, remark) (id, workerFk, centerFk, `date`, `time`, isFit, amount, invoice, remark)
VALUES(3, 9, 2, '2000-01-01', '8:00', 1, 150.0, NULL, NULL); VALUES(3, 9, 2, '2000-01-01', '8:00', 1, 150.0, NULL, NULL);
INSERT INTO vn.stockBought (workerFk, bought, reserve, dated) INSERT INTO vn.stockBought (workerFk, bought, reserve, dated)
VALUES(35, 1.00, 1.00, '2001-01-01'); VALUES(35, 1.00, 1.00, '2001-01-01');
INSERT INTO vn.auctionConfig (id,conversionCoefficient,warehouseFk) INSERT INTO vn.auctionConfig (id,conversionCoefficient,warehouseFk)
VALUES (1,0.6,6); VALUES (1,0.6,6);
INSERT INTO vn.payrollComponent INSERT INTO vn.payrollComponent

View File

@ -6,25 +6,27 @@ BLOCK1: BEGIN
DECLARE vShipped DATE; DECLARE vShipped DATE;
DECLARE vPreviousShipped DATE; DECLARE vPreviousShipped DATE;
DECLARE vDone boolean; DECLARE vDone boolean;
DECLARE cur cursor for
DECLARE cur CURSOR FOR
SELECT clientFk, firstShipped SELECT clientFk, firstShipped
FROM bs.clientNewBorn; FROM bs.clientNewBorn;
DECLARE continue HANDLER FOR NOT FOUND SET vDone = TRUE; DECLARE continue HANDLER FOR NOT FOUND SET vDone = TRUE;
SET vDone := FALSE; SET vDone := FALSE;
DELETE FROM bs.clientNewBorn WHERE isModified = FALSE; DELETE FROM bs.clientNewBorn WHERE isModified = FALSE;
INSERT INTO clientNewBorn(clientFk, firstShipped, lastShipped) INSERT INTO clientNewBorn(clientFk, firstShipped, lastShipped)
SELECT c.id, MAX(t.shipped), MAX(t.shipped) SELECT c.id, DATE(MAX(t.shipped)), DATE(MAX(t.shipped))
FROM vn.client c FROM vn.client c
JOIN vn.ticket t on t.clientFk = c.id JOIN vn.ticket t ON t.clientFk = c.id
LEFT JOIN clientNewBorn cb on cb.clientFk = c.id LEFT JOIN clientNewBorn cb ON cb.clientFk = c.id
WHERE t.shipped BETWEEN TIMESTAMPADD(YEAR, -1, util.VN_CURDATE()) AND util.VN_CURDATE() AND cb.isModified is null WHERE t.shipped BETWEEN util.VN_CURDATE() - INTERVAL 1 YEAR
GROUP BY c.id; AND util.VN_CURDATE()
AND cb.isModified IS NULL
GROUP BY c.id;
OPEN cur; OPEN cur;
LOOP1: LOOP LOOP1: LOOP
SET vDone := FALSE; SET vDone := FALSE;
FETCH cur INTO vClientFk, vShipped; FETCH cur INTO vClientFk, vShipped;

View File

@ -22,7 +22,6 @@ BEGIN
DECLARE vItemFk INT; DECLARE vItemFk INT;
DECLARE vConcept VARCHAR(30); DECLARE vConcept VARCHAR(30);
DECLARE vAmount INT; DECLARE vAmount INT;
DECLARE vAvailable INT;
DECLARE vPrice DECIMAL(10,2); DECLARE vPrice DECIMAL(10,2);
DECLARE vSaleFk INT; DECLARE vSaleFk INT;
DECLARE vRowFk INT; DECLARE vRowFk INT;
@ -32,7 +31,6 @@ BEGIN
DECLARE vClientFk INT; DECLARE vClientFk INT;
DECLARE vCompanyFk INT; DECLARE vCompanyFk INT;
DECLARE vAgencyModeFk INT; DECLARE vAgencyModeFk INT;
DECLARE vCalcFk INT;
DECLARE vIsTaxDataChecked BOOL; DECLARE vIsTaxDataChecked BOOL;
DECLARE vDates CURSOR FOR DECLARE vDates CURSOR FOR
@ -109,7 +107,7 @@ BEGIN
) INTO vHas0Amount; ) INTO vHas0Amount;
IF vHas0Amount THEN IF vHas0Amount THEN
CALL util.throw('Remove lines with quantity = 0 before confirming'); CALL util.throw('Hay líneas vacías. Por favor, elimínelas');
END IF; END IF;
START TRANSACTION; START TRANSACTION;

View File

@ -4,7 +4,7 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `hedera`.`orderRow_afterIns
FOR EACH ROW FOR EACH ROW
BEGIN BEGIN
UPDATE `order` UPDATE `order`
SET rowUpdated = NOW() SET rowUpdated = util.VN_NOW()
WHERE id = NEW.orderFk; WHERE id = NEW.orderFk;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -4,5 +4,8 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `salix`.`ACL_beforeInsert`
FOR EACH ROW FOR EACH ROW
BEGIN BEGIN
SET NEW.editorFk = account.myUser_getId(); SET NEW.editorFk = account.myUser_getId();
IF NEW.`property` = '*' THEN
CALL util.throw('The property field cannot be *');
END IF;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` EVENT `vn`.`itemCampaig_add`
ON SCHEDULE EVERY 1 DAY
STARTS '2024-10-18 03:00:00.000'
ON COMPLETION PRESERVE
ENABLE
DO CALL itemCampaign_add()$$
DELIMITER ;

View File

@ -0,0 +1,31 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION `vn`.`buy_getUltimate`(
vItemFk INT,
vWarehouseFk INT,
vDated DATE
)
RETURNS int(11)
DETERMINISTIC
BEGIN
/**
* Calcula las últimas compras realizadas hasta una fecha.
*
* @param vItemFk Id del artículo
* @param vWarehouseFk Id del almacén
* @param vDated Compras hasta fecha
* @return Id de compra
*/
DECLARE vBuyFk INT;
CALL buy_getUltimate(vItemFk, vWarehouseFk, vDated);
SELECT buyFk INTO vBuyFk
FROM tmp.buyUltimate;
DROP TEMPORARY TABLE IF EXISTS
tmp.buyUltimate,
tmp.buyUltimateFromInterval;
RETURN vBuyFk;
END$$
DELIMITER ;

View File

@ -1,23 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION `vn`.`workerMachinery_isRegistered`(vWorkerFk VARCHAR(10))
RETURNS tinyint(1)
NOT DETERMINISTIC
READS SQL DATA
BEGIN
/**
* Comprueba si existen registros en las últimas horas (maxHours de machineWorkerConfig) del trabajador vWorkerFk y si tiene a nulo la hora outTimed (indica la hora que deja el vehículo)
*
* @param vWorkerFk id del trabajador
* @return Devuelve TRUE/FALSE en caso de que haya o no registros
*/
IF (SELECT COUNT(*)
FROM machineWorker m
WHERE m.workerFk = vWorkerFk
AND m.inTimed >= TIMESTAMPADD(HOUR , -(SELECT maxHours from machineWorkerConfig), util.VN_NOW()) AND ISNULL(m.outTimed))
THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END$$
DELIMITER ;

View File

@ -1,7 +1,7 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`buy_getUltimate`( CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`buy_getUltimate`(
vItemFk INT, vItemFk INT,
vWarehouseFk SMALLINT, vWarehouseFk INT,
vDated DATE vDated DATE
) )
BEGIN BEGIN

View File

@ -34,22 +34,19 @@ BEGIN
DECLARE vIsTaxDataChecked TINYINT(1); DECLARE vIsTaxDataChecked TINYINT(1);
DECLARE vHasCoreVnl BOOLEAN; DECLARE vHasCoreVnl BOOLEAN;
DECLARE vMandateTypeFk INT; DECLARE vMandateTypeFk INT;
DECLARE vHasDailyInvoice BOOLEAN;
SELECT cc.defaultPayMethodFk, SELECT cc.defaultPayMethodFk,
cc.defaultDueDay, cc.defaultDueDay,
cc.defaultCredit, cc.defaultCredit,
cc.defaultIsTaxDataChecked, cc.defaultIsTaxDataChecked,
cc.defaultHasCoreVnl, cc.defaultHasCoreVnl,
cc.defaultMandateTypeFk, cc.defaultMandateTypeFk
c.hasDailyInvoice
INTO vPayMethodFk, INTO vPayMethodFk,
vDueDay, vDueDay,
vDefaultCredit, vDefaultCredit,
vIsTaxDataChecked, vIsTaxDataChecked,
vHasCoreVnl, vHasCoreVnl,
vMandateTypeFk, vMandateTypeFk
vHasDailyInvoice
FROM clientConfig cc FROM clientConfig cc
LEFT JOIN province p ON p.id = vProvinceFk LEFT JOIN province p ON p.id = vProvinceFk
LEFT JOIN country c ON c.id = p.countryFk; LEFT JOIN country c ON c.id = p.countryFk;
@ -70,8 +67,7 @@ BEGIN
credit = vDefaultCredit, credit = vDefaultCredit,
isTaxDataChecked = vIsTaxDataChecked, isTaxDataChecked = vIsTaxDataChecked,
hasCoreVnl = vHasCoreVnl, hasCoreVnl = vHasCoreVnl,
isEqualizated = FALSE, isEqualizated = FALSE
hasDailyInvoice = vHasDailyInvoice
ON duplicate KEY UPDATE ON duplicate KEY UPDATE
payMethodFk = vPayMethodFk, payMethodFk = vPayMethodFk,
dueDay = vDueDay, dueDay = vDueDay,

View File

@ -37,23 +37,23 @@ BEGIN
WHERE t.id = vTicketFk; WHERE t.id = vTicketFk;
CALL cache.available_refresh( CALL cache.available_refresh(
vCacheAvailableFk, vCacheAvailableFk,
FALSE, FALSE,
vWarehouseFk, vWarehouseFk,
util.VN_CURDATE()); util.VN_CURDATE());
SELECT available INTO vAvailable SELECT available INTO vAvailable
FROM cache.available FROM cache.available
WHERE calc_id = vCacheAvailableFk WHERE calc_id = vCacheAvailableFk
AND item_id = vItemFk; AND item_id = vItemFk;
IF vAvailable < vQuantity THEN IF vAvailable < vQuantity THEN
SET vHasThrow = TRUE; SET vHasThrow = TRUE;
ELSE ELSE
SELECT `name`, SELECT `name`,
CONCAT(getUser(), ' ', DATE_FORMAT(util.VN_NOW(), '%H:%i'), ' ', name) CONCAT(getUser(), ' ', DATE_FORMAT(util.VN_NOW(), '%H:%i'), ' ', name)
INTO vItemName, vConcept INTO vItemName, vConcept
FROM item FROM item
WHERE id = vItemFk; WHERE id = vItemFk;
START TRANSACTION; START TRANSACTION;
@ -69,7 +69,7 @@ BEGIN
CALL sale_calculateComponent(vSaleFk, NULL); CALL sale_calculateComponent(vSaleFk, NULL);
CALL itemShelvingSale_addBySale(vSaleFk, vSectorFk); CALL itemShelvingSale_addBySale(vSaleFk, vSectorFk);
IF NOT EXISTS (SELECT TRUE FROM itemShelvingSale WHERE saleFk = vSaleFk LIMIT 1) THEN IF NOT EXISTS (SELECT TRUE FROM itemShelvingSale WHERE saleFk = vSaleFk LIMIT 1) THEN
SET vHasThrow = TRUE; SET vHasThrow = TRUE;
END IF; END IF;
@ -78,13 +78,13 @@ BEGIN
IF vHasThrow THEN IF vHasThrow THEN
CALL util.throw("There is no available for the selected item"); CALL util.throw("There is no available for the selected item");
END IF; END IF;
IF vSaleGroupFk THEN IF vSaleGroupFk THEN
INSERT INTO saleGroupDetail INSERT INTO saleGroupDetail
SET saleFk = vSaleFk, SET saleFk = vSaleFk,
saleGroupFk = vSaleGroupFk; saleGroupFk = vSaleGroupFk;
END IF; END IF;
COMMIT; COMMIT;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -5,100 +5,139 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_getAssigne
) )
BEGIN BEGIN
/** /**
* Comprueba si existen colecciones libres que se ajustan al perfil del usuario * Comprueba si existen colecciones libres que se ajustan
* y le asigna la más antigua. * al perfil del usuario y le asigna la más antigua.
* Añade un registro al semillero de colecciones y hace la reserva para la colección * Añade un registro al semillero de colecciones.
* *
* @param vUserFk Id de usuario * @param vUserFk Id de usuario
* @param vCollectionFk Id de colección * @param vCollectionFk Id de colección
*/ */
DECLARE vHasTooMuchCollections BOOL; DECLARE vHasTooMuchCollections BOOL;
DECLARE vItemPackingTypeFk VARCHAR(1); DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vWarehouseFk INT; DECLARE vCollectionWorker INT;
DECLARE vLockName VARCHAR(215); DECLARE vMaxNotAssignedCollectionLifeTime TIME;
DECLARE vLockTime INT DEFAULT 30;
DECLARE vCollections CURSOR FOR
WITH collections AS (
SELECT tc.collectionFk,
SUM(sv.volume) volume,
c.saleTotalCount,
c.itemPackingTypeFk,
c.trainFk,
c.warehouseFk,
c.wagons
FROM vn.ticketCollection tc
JOIN vn.collection c ON c.id = tc.collectionFk
JOIN vn.saleVolume sv ON sv.ticketFk = tc.ticketFk
WHERE c.workerFk IS NULL
AND sv.shipped >= util.VN_CURDATE()
GROUP BY tc.collectionFk
) SELECT c.collectionFk
FROM collections c
JOIN vn.operator o
WHERE o.workerFk = vUserFk
AND (c.saleTotalCount <= o.linesLimit OR o.linesLimit IS NULL)
AND (c.itemPackingTypeFk = o.itemPackingTypeFk OR o.itemPackingTypeFk IS NULL)
AND o.numberOfWagons = c.wagons
AND o.trainFk = c.trainFk
AND o.warehouseFk = c.warehouseFk;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
-- Si hay colecciones sin terminar, sale del proceso
DECLARE EXIT HANDLER FOR SQLEXCEPTION DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN BEGIN
IF vLockName IS NOT NULL THEN ROLLBACK;
DO RELEASE_LOCK(vLockName);
END IF;
RESIGNAL; RESIGNAL;
END; END;
-- Si hay colecciones sin terminar, sale del proceso
CALL collection_get(vUserFk); CALL collection_get(vUserFk);
SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, pc.maxNotAssignedCollectionLifeTime
pc.collection_assign_lockname INTO vHasTooMuchCollections, vMaxNotAssignedCollectionLifeTime
INTO vHasTooMuchCollections, FROM productionConfig pc
vLockName LEFT JOIN tmp.collection ON TRUE;
FROM tmp.collection c
JOIN productionConfig pc;
DROP TEMPORARY TABLE tmp.collection; DROP TEMPORARY TABLE tmp.collection;
IF vHasTooMuchCollections THEN IF vHasTooMuchCollections THEN
CALL util.throw('There are pending collections'); CALL util.throw('Hay colecciones pendientes');
END IF;
SELECT warehouseFk, itemPackingTypeFk
INTO vWarehouseFk, vItemPackingTypeFk
FROM operator
WHERE workerFk = vUserFk;
SET vLockName = CONCAT_WS('/',
vLockName,
vWarehouseFk,
vItemPackingTypeFk
);
IF NOT GET_LOCK(vLockName, vLockTime) THEN
CALL util.throw(CONCAT('Cannot get lock: ', vLockName));
END IF; END IF;
-- Se eliminan las colecciones sin asignar que estan obsoletas -- Se eliminan las colecciones sin asignar que estan obsoletas
INSERT INTO ticketTracking(stateFk, ticketFk)
SELECT s.id, tc.ticketFk
FROM collection c
JOIN ticketCollection tc ON tc.collectionFk = c.id
JOIN state s ON s.code = 'PRINTED_AUTO'
JOIN productionConfig pc
WHERE c.workerFk IS NULL
AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime;
DELETE c INSERT INTO ticketTracking(stateFk, ticketFk)
FROM collection c SELECT s.id, tc.ticketFk
JOIN productionConfig pc FROM `collection` c
WHERE c.workerFk IS NULL JOIN ticketCollection tc ON tc.collectionFk = c.id
AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime; JOIN `state` s ON s.code = 'PRINTED_AUTO'
WHERE c.workerFk IS NULL
AND TIMEDIFF(util.VN_NOW(), c.created) > vMaxNotAssignedCollectionLifeTime;
DELETE FROM `collection`
WHERE workerFk IS NULL
AND TIMEDIFF(util.VN_NOW(), created) > vMaxNotAssignedCollectionLifeTime;
-- Se añade registro al semillero -- Se añade registro al semillero
INSERT INTO collectionHotbed
SET userFk = vUserFk; INSERT INTO collectionHotbed(userFk) VALUES(vUserFk);
-- Comprueba si hay colecciones disponibles que se ajustan a su configuracion -- Comprueba si hay colecciones disponibles que se ajustan a su configuracion
SELECT MIN(c.id) INTO vCollectionFk
FROM collection c OPEN vCollections;
JOIN operator o ON (o.itemPackingTypeFk = c.itemPackingTypeFk l: LOOP
OR c.itemPackingTypeFk IS NULL) SET vDone = FALSE;
AND o.numberOfWagons = c.wagons FETCH vCollections INTO vCollectionFk;
AND o.trainFk = c.trainFk
AND o.warehouseFk = c.warehouseFk IF vDone THEN
AND c.workerFk IS NULL LEAVE l;
WHERE o.workerFk = vUserFk; END IF;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET vCollectionFk = NULL;
RESIGNAL;
END;
START TRANSACTION;
SELECT workerFk INTO vCollectionWorker
FROM `collection`
WHERE id = vCollectionFk FOR UPDATE;
IF vCollectionWorker IS NULL THEN
UPDATE `collection`
SET workerFk = vUserFk
WHERE id = vCollectionFk;
COMMIT;
LEAVE l;
END IF;
ROLLBACK;
END;
END LOOP;
CLOSE vCollections;
IF vCollectionFk IS NULL THEN IF vCollectionFk IS NULL THEN
CALL collection_new(vUserFk, vCollectionFk); CALL collection_new(vUserFk, vCollectionFk);
START TRANSACTION;
SELECT workerFk INTO vCollectionWorker
FROM `collection`
WHERE id = vCollectionFk FOR UPDATE;
IF vCollectionWorker IS NULL THEN
UPDATE `collection`
SET workerFk = vUserFk
WHERE id = vCollectionFk;
END IF;
COMMIT;
END IF; END IF;
UPDATE collection
SET workerFk = vUserFk
WHERE id = vCollectionFk;
CALL itemShelvingSale_addByCollection(vCollectionFk); CALL itemShelvingSale_addByCollection(vCollectionFk);
DO RELEASE_LOCK(vLockName);
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -0,0 +1,54 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`itemCampaign_add`()
proc: BEGIN
/**
* Añade registros a tabla itemCampaign.
*
* @param vDateFrom Fecha desde
* @param vDateTo Fecha hasta
* @param vCampaign Código de la campaña
*/
DECLARE vYesterday DATE;
DECLARE vCampaign VARCHAR(100);
DECLARE vScopeDays INT;
DECLARE vPreviousDays INT;
DECLARE vDateSumFrom DATE;
DECLARE vDateSumTo DATE;
SET vYesterday = util.yesterday();
SELECT dated, code, scopeDays, previousDays
INTO vDateSumTo, vCampaign, vScopeDays, vPreviousDays
FROM campaign
WHERE dated >= vYesterday
ORDER BY dated
LIMIT 1;
IF vCampaign IS NULL THEN
CALL util.throw('Missing data in campaign table');
END IF;
IF NOT vYesterday BETWEEN vDateSumTo - INTERVAL vPreviousDays DAY
AND vDateSumTo THEN
LEAVE proc;
END IF;
SET vDateSumFrom = vDateSumTo - INTERVAL vScopeDays DAY;
SET vDateSumTo = vDateSumTo - INTERVAL 1 DAY;
INSERT INTO itemCampaign(dated, itemFk, quantity, total, campaign)
SELECT vYesterday,
s.itemFk,
SUM(s.quantity) quantity,
SUM((s.quantity * s.price) * (100 - s.discount) / 100) total,
vCampaign
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
JOIN client c ON c.id = t.clientFk
WHERE t.shipped BETWEEN vDateSumFrom AND util.dayEnd(vDateSumTo)
AND c.typeFk = 'normal'
AND NOT t.isDeleted
GROUP BY s.itemFk
HAVING quantity;
END$$
DELIMITER ;

View File

@ -18,8 +18,9 @@ proc: BEGIN
DECLARE vReservedQuantity INT; DECLARE vReservedQuantity INT;
DECLARE vOutStanding INT; DECLARE vOutStanding INT;
DECLARE vUserFk INT; DECLARE vUserFk INT;
DECLARE vTotalReservedQuantity INT; DECLARE vTotalReservedQuantity INT;
DECLARE vSaleQuantity INT; DECLARE vSaleQuantity INT;
DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction;
DECLARE vItemShelvingAvailable CURSOR FOR DECLARE vItemShelvingAvailable CURSOR FOR
SELECT ish.id itemShelvingFk, SELECT ish.id itemShelvingFk,
@ -29,7 +30,7 @@ proc: BEGIN
JOIN shelving sh ON sh.code = ish.shelvingFk JOIN shelving sh ON sh.code = ish.shelvingFk
JOIN parking p ON p.id = sh.parkingFk JOIN parking p ON p.id = sh.parkingFk
JOIN sector sc ON sc.id = p.sectorFk JOIN sector sc ON sc.id = p.sectorFk
JOIN productionConfig pc JOIN productionConfig pc
WHERE s.id = vSaleFk WHERE s.id = vSaleFk
AND NOT sc.isHideForPickers AND NOT sc.isHideForPickers
AND (sc.id = vSectorFk OR vSectorFk IS NULL) AND (sc.id = vSectorFk OR vSectorFk IS NULL)
@ -44,15 +45,15 @@ proc: BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN BEGIN
ROLLBACK; CALL util.tx_rollback(vIsRequiredTx);
RESIGNAL; RESIGNAL;
END; END;
START TRANSACTION; CALL util.tx_start(vIsRequiredTx);
SELECT id INTO vSaleFk SELECT id INTO vSaleFk
FROM sale FROM sale
WHERE id = vSaleFk WHERE id = vSaleFk
FOR UPDATE; FOR UPDATE;
SELECT MAX(p.pickingOrder), s.quantity - SUM(IFNULL(iss.quantity, 0)), s.quantity SELECT MAX(p.pickingOrder), s.quantity - SUM(IFNULL(iss.quantity, 0)), s.quantity
@ -65,7 +66,7 @@ proc: BEGIN
WHERE s.id = vSaleFk; WHERE s.id = vSaleFk;
IF vOutStanding <= 0 THEN IF vOutStanding <= 0 THEN
COMMIT; CALL util.tx_commit(vIsRequiredTx);
LEAVE proc; LEAVE proc;
END IF; END IF;
@ -85,7 +86,7 @@ proc: BEGIN
IF vTotalReservedQuantity <> vSaleQuantity THEN IF vTotalReservedQuantity <> vSaleQuantity THEN
CALL util.debugAdd('itemShelvingSale_addBySale', CALL util.debugAdd('itemShelvingSale_addBySale',
CONCAT(vSaleFk, ' - ', vSaleQuantity,' - ', vTotalReservedQuantity,'-', vOutStanding,'-', account.myUser_getId())); CONCAT(vSaleFk, ' - ', vSaleQuantity,' - ', vTotalReservedQuantity,'-', vOutStanding,'-', account.myUser_getId()));
UPDATE sale UPDATE sale
SET quantity = vTotalReservedQuantity SET quantity = vTotalReservedQuantity
WHERE id = vSaleFk; WHERE id = vSaleFk;
@ -93,7 +94,7 @@ proc: BEGIN
LEAVE l; LEAVE l;
END IF; END IF;
SELECT id INTO vItemShelvingFk SELECT id INTO vItemShelvingFk
FROM itemShelving FROM itemShelving
WHERE id = vItemShelvingFk WHERE id = vItemShelvingFk
FOR UPDATE; FOR UPDATE;
@ -102,19 +103,19 @@ proc: BEGIN
SET vOutStanding = vOutStanding - vReservedQuantity; SET vOutStanding = vOutStanding - vReservedQuantity;
IF vReservedQuantity > 0 THEN IF vReservedQuantity > 0 THEN
CALL util.debugAdd('itemShelvingSale_addBySale_reservedQuantity', CALL util.debugAdd('itemShelvingSale_addBySale_reservedQuantity',
CONCAT(vSaleFk, ' - ', vReservedQuantity, ' - ', vOutStanding, account.myUser_getId())); CONCAT(vSaleFk, ' - ', vReservedQuantity, ' - ', vOutStanding, account.myUser_getId()));
INSERT INTO itemShelvingSale( INSERT INTO itemShelvingSale(
itemShelvingFk, itemShelvingFk,
saleFk, saleFk,
quantity, quantity,
userFk, userFk,
isPicked) isPicked)
SELECT vItemShelvingFk, SELECT vItemShelvingFk,
vSaleFk, vSaleFk,
vReservedQuantity, vReservedQuantity,
vUserFk, vUserFk,
FALSE; FALSE;
UPDATE itemShelving UPDATE itemShelving
SET available = available - vReservedQuantity SET available = available - vReservedQuantity
@ -123,6 +124,6 @@ proc: BEGIN
END IF; END IF;
END LOOP; END LOOP;
CLOSE vItemShelvingAvailable; CLOSE vItemShelvingAvailable;
COMMIT; CALL util.tx_commit(vIsRequiredTx);
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -24,6 +24,7 @@ BEGIN
CALL cache.available_refresh(vAvailableCalcFk, FALSE, vWarehouseFk, vDated); CALL cache.available_refresh(vAvailableCalcFk, FALSE, vWarehouseFk, vDated);
CALL cache.visible_refresh(vVisibleCalcFk, FALSE, vWarehouseFk); CALL cache.visible_refresh(vVisibleCalcFk, FALSE, vWarehouseFk);
CALL buy_getUltimate(NULL, vWarehouseFk, vDated);
WITH itemTags AS ( WITH itemTags AS (
SELECT i.id, SELECT i.id,
@ -74,14 +75,13 @@ BEGIN
AND a.calc_id = vAvailableCalcFk AND a.calc_id = vAvailableCalcFk
LEFT JOIN cache.visible v ON v.item_id = i.id LEFT JOIN cache.visible v ON v.item_id = i.id
AND v.calc_id = vVisibleCalcFk AND v.calc_id = vVisibleCalcFk
LEFT JOIN cache.last_buy lb ON lb.item_id = i.id LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = i.id
AND lb.warehouse_id = vWarehouseFk
LEFT JOIN vn.itemProposal ip ON ip.mateFk = i.id LEFT JOIN vn.itemProposal ip ON ip.mateFk = i.id
AND ip.itemFk = vSelf AND ip.itemFk = vSelf
LEFT JOIN vn.itemTag it ON it.itemFk = i.id LEFT JOIN vn.itemTag it ON it.itemFk = i.id
AND it.priority = vPriority AND it.priority = vPriority
LEFT JOIN vn.tag t ON t.id = it.tagFk LEFT JOIN vn.tag t ON t.id = it.tagFk
LEFT JOIN vn.buy b ON b.id = lb.buy_id LEFT JOIN vn.buy b ON b.id = bu.buyFk
JOIN itemTags its JOIN itemTags its
WHERE a.available > 0 WHERE a.available > 0
AND (i.typeFk = its.typeFk OR NOT vShowType) AND (i.typeFk = its.typeFk OR NOT vShowType)
@ -98,5 +98,7 @@ BEGIN
(i.tag8 = its.tag8) DESC, (i.tag8 = its.tag8) DESC,
match8 DESC match8 DESC
LIMIT 100; LIMIT 100;
DROP TEMPORARY TABLE tmp.buyUltimate;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -1,22 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`machineWorker_add`(vPlate VARCHAR(10), vWorkerFk INT)
BEGIN
/**
* Inserta registro si el vWorkerFk no ha registrado nada en las últimas 12 horas
* @param vPlate número de matrícula
* @param vWorkerFk id del worker
*
*/
UPDATE vn.machineWorker mw
JOIN vn.machine m ON m.id = mw.machineFk
SET mw.outTimed = util.VN_NOW()
WHERE (mw.workerFk = vWorkerFk OR m.plate = vPlate)
AND ISNULL(mw.outTimed);
INSERT INTO machineWorker (machineFk, workerFk)
SELECT m.id, vWorkerFk
FROM machine m
WHERE m.plate= vPlate;
END$$
DELIMITER ;

View File

@ -1,21 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`machineWorker_getHistorical`(vPlate VARCHAR(20), vWorkerFk INT)
BEGIN
/**
* Obtiene historial de la matrícula vPlate que el trabajador vWorkerFk escanea,
* si es jefe de producción muestra el historial completo.
*
* @param vPlate número de matrícula
* @param vWorkerFk id del trabajador
*
*/
DECLARE vWorkerName VARCHAR(255) DEFAULT account.user_getNameFromId(vWorkerFk);
SELECT mw.inTimed,account.user_getNameFromId(mw.workerFk) as workerName, mw.outTimed
FROM machineWorker mw
JOIN machine m ON m.plate = vPlate
WHERE mw.machineFk = m.id
AND mw.workerFk = IF(account.user_hasRole(vWorkerName, 'coolerAssist'), mw.workerFk, vWorkerFk)
ORDER BY mw.inTimed DESC;
END$$
DELIMITER ;

View File

@ -1,38 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`machineWorker_update`(vPlate VARCHAR(10), vWorkerFk INT)
BEGIN
/**
* Actualiza el registro correspondiente si el vWorkerFk se ha registrado en las últimas horas (campo maxHours de machineWorkerConfig) con vPlate,
*
* @param vPlate número de matrícula
* @param vWorkerFk id del trabajador
*
*/
DECLARE vMachineFk INT(10);
DECLARE vMaxHours INT(10);
SELECT m.id INTO vMachineFk
FROM machine m
WHERE m.plate = vPlate;
SELECT maxHours INTO vMaxHours
FROM machineWorkerConfig;
IF (SELECT COUNT(*)
FROM machineWorker m
WHERE m.workerFk = vWorkerFk
AND m.inTimed >= TIMESTAMPADD(HOUR , -vMaxHours, util.VN_NOW()) AND ISNULL(m.outTimed)) THEN
UPDATE machineWorker m
SET m.outTimed = CURRENT_TIMESTAMP()
WHERE m.workerFk = vWorkerFk
AND m.inTimed >= TIMESTAMPADD(HOUR , -vMaxHours, util.VN_NOW())
AND ISNULL(m.outTimed)
AND m.machineFk = vMachineFk;
END IF;
END$$
DELIMITER ;

View File

@ -1,16 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`machine_getWorkerPlate`(vWorkerFk INT)
BEGIN
/**
* Selecciona la matrícula del vehículo del workerfk
*
* @param vWorkerFk el id del trabajador
*/
SELECT m.plate
FROM machine m
JOIN machineWorker mw ON mw.machineFk = m.id
WHERE mw.inTimed >= TIMESTAMPADD(HOUR , -12,util.VN_NOW())
AND ISNULL(mw.outTimed)
AND mw.workerFk = vWorkerFk;
END$$
DELIMITER ;

View File

@ -0,0 +1,20 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`saleTracking_sectorCollectionAddPrevOK`(
vSectorCollectionFk INT
)
BEGIN
/**
* Inserta los registros de sectorCollection con el estado PREVIA OK si la reserva está picked
*
* @param vSectorCollectionFk Identificador de vn.sectorCollection
*/
REPLACE saleTracking(saleFk, isChecked, workerFk, stateFk)
SELECT sgd.saleFk, TRUE, sc.userFk, s.id
FROM sectorCollection sc
JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id
JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk
JOIN state s ON s.code = 'OK PREVIOUS'
JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk
WHERE sc.id = vSectorCollectionFk AND iss.isPicked;
END$$
DELIMITER ;

View File

@ -51,7 +51,8 @@ BEGIN
origin.companyFk futureCompanyFk, origin.companyFk futureCompanyFk,
IFNULL(dest.nickname, origin.nickname) nickname, IFNULL(dest.nickname, origin.nickname) nickname,
dest.landed, dest.landed,
dest.preparation dest.preparation,
origin.departmentFk
FROM ( FROM (
SELECT s.ticketFk, SELECT s.ticketFk,
c.salesPersonFk workerFk, c.salesPersonFk workerFk,
@ -71,9 +72,11 @@ BEGIN
t.addressFk, t.addressFk,
t.warehouseFk, t.warehouseFk,
t.companyFk, t.companyFk,
t.agencyModeFk t.agencyModeFk,
wd.departmentFk
FROM ticket t FROM ticket t
JOIN client c ON c.id = t.clientFk JOIN client c ON c.id = t.clientFk
JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN saleVolume sv ON sv.saleFk = s.id JOIN saleVolume sv ON sv.saleFk = s.id
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk

View File

@ -43,7 +43,7 @@ BEGIN
c.isTaxDataChecked, c.isTaxDataChecked,
t.companyFk, t.companyFk,
t.shipped, t.shipped,
IFNULL(a.hasDailyInvoice, co.hasDailyInvoice), c.hasDailyInvoice,
w.isManaged, w.isManaged,
c.hasToInvoice c.hasToInvoice
INTO vClientFk, INTO vClientFk,
@ -55,9 +55,6 @@ BEGIN
vHasToInvoice vHasToInvoice
FROM ticket t FROM ticket t
JOIN `client` c ON c.id = t.clientFk JOIN `client` c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk
LEFT JOIN autonomy a ON a.id = p.autonomyFk
JOIN country co ON co.id = p.countryFk
JOIN warehouse w ON w.id = t.warehouseFk JOIN warehouse w ON w.id = t.warehouseFk
WHERE t.id = vCurTicketFk; WHERE t.id = vCurTicketFk;
@ -85,7 +82,7 @@ BEGIN
IF(vHasDailyInvoice) AND vHasToInvoice THEN IF(vHasDailyInvoice) AND vHasToInvoice THEN
SELECT invoiceSerial(vClientFk, vCompanyFk, 'quick') INTO vSerial; SELECT invoiceSerial(vClientFk, vCompanyFk, 'quick') INTO vSerial;
IF vSerial IS NULL THEN IF vSerial IS NULL THEN
CALL util.throw('Cannot booking without a serial'); CALL util.throw('Cannot booking without a serial');
END IF; END IF;

View File

@ -1,5 +1,7 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_getTax`(IN vTaxArea VARCHAR(25)) CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_getTax`(
vTaxArea VARCHAR(25)
)
BEGIN BEGIN
/** /**
* Calcula la base imponible, el IVA y el recargo de equivalencia para * Calcula la base imponible, el IVA y el recargo de equivalencia para
@ -33,30 +35,39 @@ BEGIN
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketTax CREATE OR REPLACE TEMPORARY TABLE tmp.ticketTax
(PRIMARY KEY (ticketFk, code, rate)) (PRIMARY KEY (ticketFk, code, rate))
ENGINE = MEMORY ENGINE = MEMORY
SELECT * FROM ( WITH sales AS (
SELECT tmpTicket.ticketFk, SELECT s.ticketFk,
bp.pgcFk, s.itemFk,
SUM(s.quantity * s.price * (100 - s.discount) / 100 ) taxableBase, s.quantity * s.price * (100 - s.discount) / 100 total,
pgc.rate, t.companyFk,
tc.code, t.addressFk,
bp.priority su.countryFk,
FROM tmp.ticket tmpTicket ata.areaFk,
JOIN sale s ON s.ticketFk = tmpTicket.ticketFk itc.taxClassFk
JOIN item i ON i.id = s.itemFk FROM vn.sale s
JOIN ticket t ON t.id = tmpTicket.ticketFk JOIN tmp.ticket tmp ON tmp.ticketFk = s.ticketFk
JOIN supplier su ON su.id = t.companyFk JOIN vn.ticket t ON t.id = s.ticketFk
JOIN vn.supplier su ON su.id = t.companyFk
JOIN tmp.addressTaxArea ata ON ata.addressFk = t.addressFk JOIN tmp.addressTaxArea ata ON ata.addressFk = t.addressFk
AND ata.companyFk = t.companyFk AND ata.companyFk = t.companyFk
JOIN itemTaxCountry itc ON itc.itemFk = i.id JOIN vn.itemTaxCountry itc ON itc.itemFk = s.itemFk
AND itc.countryFk = su.countryFk AND itc.countryFk = su.countryFk
JOIN bookingPlanner bp ON bp.countryFk = su.countryFk HAVING total
AND bp.taxAreaFk = ata.areaFk )
AND bp.taxClassFk = itc.taxClassFk SELECT s.ticketFk,
JOIN pgc ON pgc.code = bp.pgcFk bp.pgcFk,
JOIN taxClass tc ON tc.id = bp.taxClassFk SUM(s.total) taxableBase,
GROUP BY tmpTicket.ticketFk, pgc.code, pgc.rate pgc.rate,
HAVING taxableBase tc.code,
) t3 bp.priority
FROM sales s
JOIN vn.bookingPlanner bp ON bp.countryFk = s.countryFk
AND bp.taxAreaFk = s.areaFk
AND bp.taxClassFk = s.taxClassFk
JOIN vn.pgc ON pgc.code = bp.pgcFk
JOIN vn.taxClass tc ON tc.id = bp.taxClassFk
GROUP BY s.ticketFk, pgc.code, pgc.rate
HAVING taxableBase
ORDER BY priority; ORDER BY priority;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketServiceTax CREATE OR REPLACE TEMPORARY TABLE tmp.ticketServiceTax

View File

@ -3,10 +3,10 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`itemShelvingSale_afterI
AFTER INSERT ON `itemShelvingSale` AFTER INSERT ON `itemShelvingSale`
FOR EACH ROW FOR EACH ROW
BEGIN BEGIN
UPDATE sale s UPDATE sale s
JOIN operator o ON o.workerFk = account.myUser_getId() JOIN operator o ON o.workerFk = account.myUser_getId()
SET s.isPicked = IF(o.isOnReservationMode, s.isPicked, TRUE) JOIN sector se ON se.id = o.sectorFk
WHERE id = NEW.saleFk; SET s.isPicked = IF(IFNULL(se.isOnReservationMode, o.isOnReservationMode), s.isPicked, TRUE)
WHERE s.id = NEW.saleFk;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -10,11 +10,10 @@ FROM (
`vn`.`collection` `c` `vn`.`collection` `c`
JOIN `vn`.`client` `cl` ON(`cl`.`id` = `c`.`workerFk`) JOIN `vn`.`client` `cl` ON(`cl`.`id` = `c`.`workerFk`)
) )
LEFT JOIN `vn`.`machineWorker` `mw` ON( JOIN `vn`.`operator` `o` ON(
`mw`.`workerFk` = `c`.`workerFk` `o`.`workerFk` = `c`.`workerFk`
AND `mw`.`inTimed` > `util`.`VN_CURDATE`()
) )
) )
WHERE `c`.`created` > `util`.`VN_CURDATE`() WHERE `c`.`created` > `util`.`VN_CURDATE`()
AND `mw`.`workerFk` IS NULL AND `o`.`machineFk` IS NULL
GROUP BY `c`.`workerFk` GROUP BY `c`.`workerFk`

View File

@ -22,7 +22,6 @@ AS SELECT `c`.`id` AS `id_cliente`,
`c`.`credit` AS `credito`, `c`.`credit` AS `credito`,
`c`.`countryFk` AS `Id_Pais`, `c`.`countryFk` AS `Id_Pais`,
`c`.`isActive` AS `activo`, `c`.`isActive` AS `activo`,
`c`.`gestdocFk` AS `gestdoc_id`,
`c`.`quality` AS `calidad`, `c`.`quality` AS `calidad`,
`c`.`payMethodFk` AS `pay_met_id`, `c`.`payMethodFk` AS `pay_met_id`,
`c`.`created` AS `created`, `c`.`created` AS `created`,

View File

@ -0,0 +1,3 @@
ALTER TABLE vn.clientObservation DROP COLUMN IF EXISTS observationTypeFk;
ALTER TABLE vn.clientObservation ADD COLUMN IF NOT EXISTS observationTypeFk TINYINT(3) UNSIGNED NULL;
ALTER TABLE vn.clientObservation ADD CONSTRAINT clientObservationTypeFk FOREIGN KEY IF NOT EXISTS (observationTypeFk) REFERENCES vn.observationType(id);

View File

@ -0,0 +1,3 @@
INSERT IGNORE INTO vn.observationType
SET description = 'Finance',
code = 'finance';

View File

@ -1,5 +1,3 @@
/*
UPDATE vn.sale UPDATE vn.sale
SET originalQuantity = quantity SET originalQuantity = quantity
WHERE originalQuantity IS NULL WHERE originalQuantity IS NULL
*/

View File

@ -1 +1 @@
-- ALTER TABLE vn.sale MODIFY COLUMN originalQuantity decimal(10,2) DEFAULT 0.00 NOT NULL COMMENT 'Se utiliza para notificar a través de rocket los cambios de quantity'; ALTER TABLE vn.sale MODIFY COLUMN originalQuantity decimal(10,2) DEFAULT 0.00 NOT NULL COMMENT 'Se utiliza para notificar a través de rocket los cambios de quantity';

View File

@ -0,0 +1,3 @@
-- Place your SQL code here
ALTER TABLE hedera.`order` ADD IF NOT EXISTS rowUpdated DATETIME NULL
COMMENT 'Timestamp for last updated record in orderRow table';

View File

@ -0,0 +1,2 @@
ALTER TABLE vn.sector ADD isOnReservationMode tinyint(1) DEFAULT FALSE NULL;

View File

@ -0,0 +1,6 @@
ALTER TABLE `vn`.`operator`
ADD COLUMN `machineFk` int(11) DEFAULT NULL,
ADD CONSTRAINT `operator_machine_FK` FOREIGN KEY (`machineFk`) REFERENCES `vn`.`machine` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('Machine','*','*','ALLOW','ROLE','productionBoss');

View File

@ -0,0 +1,4 @@
ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS username varchar(100) NULL;
ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS password varchar(100) NULL;
ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS token text NULL;
ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS expired int(11) NULL;

View File

@ -0,0 +1,3 @@
-- Place your SQL code here
ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving;
ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL;

View File

@ -0,0 +1,3 @@
ALTER TABLE `vn`.`ticketConfig`
ADD COLUMN `closureDaysAgo` int(11) NOT NULL DEFAULT 2 COMMENT 'Number of days to look back for ticket closure',
ADD CONSTRAINT `closureDaysAgo_check` CHECK (`closureDaysAgo` > 0);

View File

@ -0,0 +1,137 @@
CREATE TABLE IF NOT EXISTS `vn`.`itemFarmingTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemFarmingTag` (`name`) VALUES ('Enraizado');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemFarmingTag'
WHERE name= 'cultivo';
CREATE TABLE IF NOT EXISTS `vn`.`itemWrappingTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Bolsa');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Caja cartón');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Caja decorativa');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Celofán');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Papel kraft');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Plástico');
INSERT IGNORE INTO `vn`.`itemWrappingTag` (`name`) VALUES ('Variable');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemWrappingTag'
WHERE name= 'Envoltorio';
CREATE TABLE IF NOT EXISTS `vn`.`itemLanguageTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Castellano');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Catalán');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Euskera');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Francés');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Gallego');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Inglés');
INSERT IGNORE INTO `vn`.`itemLanguageTag` (`name`) VALUES ('Portugués');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemLanguageTag'
WHERE name= 'Idioma';
CREATE TABLE IF NOT EXISTS `vn`.`itemStemTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemStemTag` (`name`) VALUES ('Natural');
INSERT IGNORE INTO `vn`.`itemStemTag` (`name`) VALUES ('Seminatural');
INSERT IGNORE INTO `vn`.`itemStemTag` (`name`) VALUES ('Sintético');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemStemTag'
WHERE name= 'Tronco';
CREATE TABLE IF NOT EXISTS `vn`.`itemBreederTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemBreederTag` (`name`) VALUES ('David Austin');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemBreederTag'
WHERE name= 'Obtentor';
CREATE TABLE IF NOT EXISTS `vn`.`itemBaseTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Biodegradable');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Caballete');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Cerámica');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Cristal');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Plástico por inyección');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Madera');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Plástico');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Rígido');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Ruedas');
INSERT IGNORE INTO `vn`.`itemBaseTag` (`name`) VALUES ('Sin soporte rígido');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemBaseTag'
WHERE name= 'Soporte';
CREATE TABLE IF NOT EXISTS `vn`.`itemVatRateTag` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT
CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT IGNORE INTO `vn`.`itemVatRateTag` (`name`) VALUES ('General');
INSERT IGNORE INTO `vn`.`itemVatRateTag` (`name`) VALUES ('Reducido');
UPDATE vn.tag
SET isFree=0,
sourceTable='itemVatRateTag'
WHERE name= 'Tipo de IVA';
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemFarmingTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemWrappingTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemLanguageTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemStemTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemWrappingTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemBaseTag TO logisticAssist;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE vn.itemBreederTag TO logisticAssist;

View File

@ -0,0 +1,13 @@
UPDATE `vn`.`client` c
JOIN `vn`.`country` co ON co.id=c.countryFk
SET c.hasDailyInvoice = co.hasDailyInvoice
WHERE co.hasDailyInvoice IS NOT NULL
AND c.hasDailyInvoice = FALSE;
UPDATE `vn`.`client` c
JOIN `vn`.`province` p ON p.id=c.provinceFk
JOIN `vn`.`autonomy` a ON a.id = p.autonomyFk
SET c.hasDailyInvoice = a.hasDailyInvoice
WHERE a.hasDailyInvoice IS NOT NULL
AND c.hasDailyInvoice = FALSE;

View File

@ -0,0 +1,25 @@
CREATE TABLE IF NOT EXISTS `vn`.`itemCampaign` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
dated date NOT NULL,
itemFk int(11) NOT NULL,
quantity decimal(10,2) NOT NULL,
total decimal(10,2) NOT NULL,
campaign varchar(100) NOT NULL,
UNIQUE KEY `itemCampaign_UNIQUE` (`dated`,`itemFk`),
CONSTRAINT itemCampaign_item_FK FOREIGN KEY (itemFk) REFERENCES vn.item(id) ON DELETE RESTRICT ON UPDATE CASCADE
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb3
COLLATE=utf8mb3_unicode_ci
COMMENT='Tallos confirmados por día en los días de más producción de una campaña. La tabla está pensada para que sea una foto.';
ALTER TABLE vn.campaign
ADD previousDays int(10) unsigned DEFAULT 30 NOT NULL COMMENT 'Días previos para calcular e insertar en la tabla itemCampaign';
UPDATE vn.campaign
SET previousDays = 90
WHERE code = 'allSaints';
UPDATE vn.campaign
SET previousDays = 60
WHERE code IN ('valentinesDay', 'mothersDay');

View File

@ -0,0 +1 @@
ALTER TABLE vn.client CHANGE gestdocFk gestdocFk__ int(11) DEFAULT NULL NULL COMMENT '@deprecated 2024-10-17';

View File

@ -0,0 +1,3 @@
DELETE FROM `salix`.`ACL`
WHERE `model` = 'Worker'
AND `property` IN ('find', 'findById', 'findOne');

View File

@ -0,0 +1,3 @@
DELETE FROM salix.ACL
WHERE property = 'labelPdf'
AND model = 'Item';

View File

@ -0,0 +1,9 @@
USE vn;
RENAME TABLE machineWorker TO machineWorker__;
ALTER TABLE machineWorker__ COMMENT = '@deprecated 2024-10-23 not used';
RENAME TABLE machineWorkerConfig TO machineWorkerConfig__;
ALTER TABLE machineWorkerConfig__ COMMENT = '@deprecated 2024-10-23 not used';
DELETE FROM salix.ACL WHERE model = 'MachineWorker';

View File

@ -0,0 +1,3 @@
INSERT INTO vn.report (name, `method`)
VALUES ('LabelItemBarcode','Items/{id}/label-barcode-pdf'),
('LabelItemQr','Items/{id}/label-qr-pdf');

View File

@ -1,42 +0,0 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer';
describe('Client Add notes path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('employee', 'client');
await page.accessToSearchResult('Bruce Banner');
await page.accessToSection('client.card.note.index');
});
afterAll(async() => {
await browser.close();
});
it(`should reach the notes index`, async() => {
await page.waitForState('client.card.note.index');
});
it(`should click on the add note button`, async() => {
await page.waitToClick(selectors.clientNotes.addNoteFloatButton);
await page.waitForState('client.card.note.create');
});
it(`should create a note`, async() => {
await page.waitForSelector(selectors.clientNotes.note);
await page.type(`${selectors.clientNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
await page.waitToClick(selectors.clientNotes.saveButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should confirm the note was created', async() => {
const result = await page.waitToGetProperty(selectors.clientNotes.firstNoteText, 'innerText');
expect(result).toEqual('Meeting with Black Widow 21st 9am');
});
});

View File

@ -28,12 +28,12 @@ describe('Client defaulter path', () => {
const salesPersonName = const salesPersonName =
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
expect(clientName).toEqual('Bruce Banner'); expect(clientName).toEqual('Ororo Munroe');
expect(salesPersonName).toEqual('developer'); expect(salesPersonName).toEqual('salesperson');
}); });
it('should first observation not changed', async() => { it('should first observation not changed', async() => {
const expectedObservation = 'Meeting with Black Widow 21st 9am'; const expectedObservation = 'Madness, as you know, is like gravity, all it takes is a little push';
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
expect(result).toContain(expectedObservation); expect(result).toContain(expectedObservation);
@ -62,13 +62,4 @@ describe('Client defaulter path', () => {
await page.write(selectors.clientDefaulter.observation, 'My new observation'); await page.write(selectors.clientDefaulter.observation, 'My new observation');
await page.waitToClick(selectors.clientDefaulter.saveButton); await page.waitToClick(selectors.clientDefaulter.saveButton);
}); });
it('should first observation changed', async() => {
const message = await page.waitForSnackbar();
await page.waitForSelector(selectors.clientDefaulter.firstObservation);
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
expect(message.text).toContain('Observation saved!');
expect(result).toContain('My new observation');
});
}); });

View File

@ -240,5 +240,6 @@
"There is already a tray with the same height": "There is already a tray with the same height", "There is already a tray with the same height": "There is already a tray with the same height",
"The height must be greater than 50cm": "The height must be greater than 50cm", "The height must be greater than 50cm": "The height must be greater than 50cm",
"The maximum height of the wagon is 200cm": "The maximum height of the wagon is 200cm", "The maximum height of the wagon is 200cm": "The maximum height of the wagon is 200cm",
"The quantity claimed cannot be greater than the quantity of the line": "The quantity claimed cannot be greater than the quantity of the line" "The quantity claimed cannot be greater than the quantity of the line": "The quantity claimed cannot be greater than the quantity of the line",
"There are tickets for this area, delete them first": "There are tickets for this area, delete them first"
} }

View File

@ -350,6 +350,7 @@
"Cmr file does not exist": "El archivo del cmr no existe", "Cmr file does not exist": "El archivo del cmr no existe",
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias", "You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
"The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas", "The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas",
"No invoice series found for these parameters": "No se encontró una serie para estos parámetros",
"The line could not be marked": "La linea no puede ser marcada", "The line could not be marked": "La linea no puede ser marcada",
"Through this procedure, it is not possible to modify the password of users with verified email": "Mediante este procedimiento, no es posible modificar la contraseña de usuarios con correo verificado", "Through this procedure, it is not possible to modify the password of users with verified email": "Mediante este procedimiento, no es posible modificar la contraseña de usuarios con correo verificado",
"They're not your subordinate": "No es tu subordinado/a.", "They're not your subordinate": "No es tu subordinado/a.",
@ -381,5 +382,8 @@
"The entry does not have stickers": "La entrada no tiene etiquetas", "The entry does not have stickers": "La entrada no tiene etiquetas",
"This buyer has already made a reservation for this date": "Este comprador ya ha hecho una reserva para esta fecha", "This buyer has already made a reservation for this date": "Este comprador ya ha hecho una reserva para esta fecha",
"No valid travel thermograph found": "No se encontró un termógrafo válido", "No valid travel thermograph found": "No se encontró un termógrafo válido",
"The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea" "The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea",
} "type cannot be blank": "Se debe rellenar el tipo",
"There are tickets for this area, delete them first": "Hay tickets para esta sección, borralos primero",
"There is no company associated with that warehouse": "No hay ninguna empresa asociada a ese almacén"
}

View File

@ -350,6 +350,7 @@
"Cmr file does not exist": "Le fichier cmr n'existe pas", "Cmr file does not exist": "Le fichier cmr n'existe pas",
"You are not allowed to modify the alias": "Vous n'êtes pas autorisé à modifier l'alias", "You are not allowed to modify the alias": "Vous n'êtes pas autorisé à modifier l'alias",
"The address of the customer must have information about Incoterms and Customs Agent": "L'adresse du client doit contenir des informations sur les Incoterms et l'agent des douanes", "The address of the customer must have information about Incoterms and Customs Agent": "L'adresse du client doit contenir des informations sur les Incoterms et l'agent des douanes",
"No invoice series found for these parameters": "Aucune série de facture trouvée pour ces paramètres",
"The line could not be marked": "La ligne ne peut pas être marquée", "The line could not be marked": "La ligne ne peut pas être marquée",
"This password can only be changed by the user themselves": "Ce mot de passe ne peut être modifié que par l'utilisateur lui-même", "This password can only be changed by the user themselves": "Ce mot de passe ne peut être modifié que par l'utilisateur lui-même",
"They're not your subordinate": "Ce n'est pas votre subordonné.", "They're not your subordinate": "Ce n'est pas votre subordonné.",

View File

@ -350,6 +350,7 @@
"Cmr file does not exist": "O arquivo CMR não existe", "Cmr file does not exist": "O arquivo CMR não existe",
"You are not allowed to modify the alias": "Você não tem permissão para modificar o alias", "You are not allowed to modify the alias": "Você não tem permissão para modificar o alias",
"The address of the customer must have information about Incoterms and Customs Agent": "O endereço do cliente deve ter informações sobre Incoterms e Agente Aduaneiro", "The address of the customer must have information about Incoterms and Customs Agent": "O endereço do cliente deve ter informações sobre Incoterms e Agente Aduaneiro",
"No invoice series found for these parameters": "Nenhuma série de fatura encontrada para esses parâmetros",
"The line could not be marked": "A linha não pôde ser marcada", "The line could not be marked": "A linha não pôde ser marcada",
"This password can only be changed by the user themselves": "Esta senha só pode ser alterada pelo próprio usuário", "This password can only be changed by the user themselves": "Esta senha só pode ser alterada pelo próprio usuário",
"They're not your subordinate": "Eles não são seus subordinados.", "They're not your subordinate": "Eles não são seus subordinados.",

View File

@ -85,16 +85,11 @@ module.exports = Self => {
const updatedClaim = await claim.updateAttributes(args, myOptions); const updatedClaim = await claim.updateAttributes(args, myOptions);
const salesPerson = claim.client().salesPersonUser(); const salesPerson = claim.client().salesPersonUser();
if (salesPerson) { if (salesPerson && args.claimStateFk) {
if (changedPickup && updatedClaim.pickup) const newState = await models.ClaimState.findById(args.claimStateFk, null, myOptions);
await notifyPickUp(ctx, salesPerson.id, claim); await notifyStateChange(ctx, salesPerson.id, claim, newState.description);
if (newState.code == 'canceled')
if (args.claimStateFk) { await notifyStateChange(ctx, claim.workerFk, claim, newState.description);
const newState = await models.ClaimState.findById(args.claimStateFk, null, myOptions);
await notifyStateChange(ctx, salesPerson.id, claim, newState.description);
if (newState.code == 'canceled')
await notifyStateChange(ctx, claim.workerFk, claim, newState.description);
}
} }
if (tx) await tx.commit(); if (tx) await tx.commit();
@ -119,18 +114,4 @@ module.exports = Self => {
}); });
await models.Chat.sendCheckingPresence(ctx, workerId, message); await models.Chat.sendCheckingPresence(ctx, workerId, message);
} }
async function notifyPickUp(ctx, workerId, claim) {
const models = Self.app.models;
const url = await models.Url.getUrl();
const $t = ctx.req.__; // $translate
const message = $t('Claim will be picked', {
claimId: claim.id,
clientName: claim.client().name,
claimUrl: `${url}claim/${claim.id}/summary`,
claimPickup: $t(claim.pickup)
});
await models.Chat.sendCheckingPresence(ctx, workerId, message);
}
}; };

View File

@ -43,6 +43,23 @@ module.exports = function(Self) {
}; };
try { try {
const province = await models.Province.findOne({
where: {id: data.provinceFk},
fields: ['autonomyFk']
});
const autonomy = province ? await models.Autonomy.findOne({
where: {id: province.autonomyFk},
fields: ['hasDailyInvoice']
}) : null;
const country = await models.Country.findOne({
where: {id: data.countryFk},
fields: ['hasDailyInvoice']
});
const hasDailyInvoice = (autonomy?.hasDailyInvoice ?? country?.hasDailyInvoice) || false;
const account = await models.VnUser.create(user, myOptions); const account = await models.VnUser.create(user, myOptions);
const client = await Self.create({ const client = await Self.create({
id: account.id, id: account.id,
@ -57,7 +74,8 @@ module.exports = function(Self) {
provinceFk: data.provinceFk, provinceFk: data.provinceFk,
countryFk: data.countryFk, countryFk: data.countryFk,
isEqualizated: data.isEqualizated, isEqualizated: data.isEqualizated,
businessTypeFk: data.businessTypeFk businessTypeFk: data.businessTypeFk,
hasDailyInvoice: hasDailyInvoice
}, myOptions); }, myOptions);
const address = await models.Address.create({ const address = await models.Address.create({

View File

@ -1,67 +1,78 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
describe('Client Create', () => { describe('Client Create', () => {
const newAccount = { let options;
userName: 'deadpool', let tx;
email: 'deadpool@marvel.com',
fi: '16195279J',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 1
};
const newAccountWithoutEmail = JSON.parse(JSON.stringify(newAccount));
delete newAccountWithoutEmail.email;
beforeAll.mockLoopBackContext(); beforeAll.mockLoopBackContext();
it(`should not find deadpool as he's not created yet`, async() => { beforeEach(async() => {
const tx = await models.Client.beginTransaction({}); tx = await models.Client.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => await tx.rollback());
it('should not find deadpool as he is not created yet', async() => {
try { try {
const options = {transaction: tx}; const account = await models.VnUser.findOne({where: {name: 'deadpool'}}, options);
const client = await models.Client.findOne({where: {name: 'Wade'}}, options);
const account = await models.VnUser.findOne({where: {name: newAccount.userName}}, options); expect(account).toBeNull();
const client = await models.Client.findOne({where: {name: newAccount.name}}, options); expect(client).toBeNull();
expect(account).toEqual(null);
expect(client).toEqual(null);
await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback(); await tx.rollback();
throw e; throw e;
} }
}); });
it('should not create a new account', async() => { it('should throw an error when creating a new account without email', async() => {
const tx = await models.Client.beginTransaction({});
let error; let error;
const newAccountWithoutEmail = {
userName: 'deadpool',
fi: '16195279J',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 1
};
try { try {
const options = {transaction: tx};
await models.Client.createWithUser(newAccountWithoutEmail, options); await models.Client.createWithUser(newAccountWithoutEmail, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e.message; error = e;
await tx.rollback();
} }
expect(error).toEqual(`An email is necessary`); expect(error.message).toEqual('An email is necessary');
}); });
it('should create a new account', async() => { it('should create a new account with dailyInvoice', async() => {
const tx = await models.Client.beginTransaction({}); const newAccount = {
userName: 'deadpool',
email: 'deadpool@marvel.com',
fi: '16195279J',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 1
};
try { try {
const options = {transaction: tx}; const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const client = await models.Client.createWithUser(newAccount, options); const client = await models.Client.createWithUser(newAccount, options);
const account = await models.VnUser.findOne({where: {name: newAccount.userName}}, options); const account = await models.VnUser.findOne({where: {name: newAccount.userName}}, options);
expect(province.autonomy().hasDailyInvoice).toBeTruthy();
expect(account.name).toEqual(newAccount.userName); expect(account.name).toEqual(newAccount.userName);
expect(client.id).toEqual(account.id); expect(client.id).toEqual(account.id);
expect(client.name).toEqual(newAccount.name); expect(client.name).toEqual(newAccount.name);
@ -69,8 +80,38 @@ describe('Client Create', () => {
expect(client.fi).toEqual(newAccount.fi); expect(client.fi).toEqual(newAccount.fi);
expect(client.socialName).toEqual(newAccount.socialName); expect(client.socialName).toEqual(newAccount.socialName);
expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk); expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk);
expect(client.hasDailyInvoice).toBeTruthy();
} catch (e) {
await tx.rollback(); await tx.rollback();
throw e;
}
});
it('should create a new account without dailyInvoice', async() => {
const newAccount = {
userName: 'deadpool',
email: 'deadpool@marvel.com',
fi: '16195279J',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 3
};
try {
const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const client = await models.Client.createWithUser(newAccount, options);
expect(province.autonomy.hasDailyInvoice).toBeFalsy();
expect(client.hasDailyInvoice).toBeFalsy();
} catch (e) { } catch (e) {
await tx.rollback(); await tx.rollback();
throw e; throw e;
@ -78,26 +119,25 @@ describe('Client Create', () => {
}); });
it('should not be able to create a user if exists', async() => { it('should not be able to create a user if exists', async() => {
const tx = await models.Client.beginTransaction({});
let error; let error;
const newAccount = {
userName: 'deadpool',
email: 'deadpool@marvel.com',
fi: '16195279J',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 1
};
try { try {
const options = {transaction: tx};
await models.Client.createWithUser(newAccount, options); await models.Client.createWithUser(newAccount, options);
const client = await models.Client.createWithUser(newAccount, options); await models.Client.createWithUser(newAccount, options);
expect(client).toBeNull();
await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback();
error = e; error = e;
} }
const errorName = error.details.codes.name[0]; expect(error.message).toContain('already exists');
expect(errorName).toEqual('uniqueness');
}); });
}); });

View File

@ -74,7 +74,8 @@ module.exports = Self => {
pm.name payMethod, pm.name payMethod,
r.finished IS NULL hasRecovery, r.finished IS NULL hasRecovery,
dp.id departmentFk, dp.id departmentFk,
dp.name departmentName dp.name departmentName,
dp.notificationEmail departmentEmail
FROM defaulter d FROM defaulter d
JOIN client c ON c.id = d.clientFk JOIN client c ON c.id = d.clientFk
JOIN country cn ON cn.id = c.countryFk JOIN country cn ON cn.id = c.countryFk

View File

@ -47,7 +47,7 @@ module.exports = Self => {
await models.Mail.create({ await models.Mail.create({
subject: $t('Comment added to client', {clientFk: defaulter.clientFk}), subject: $t('Comment added to client', {clientFk: defaulter.clientFk}),
body: body, body: body,
receiver: `${defaulter.salesPersonName}@verdnatura.es`, receiver: `${defaulter.departmentEmail}`,
replyTo: `${user.name}@verdnatura.es` replyTo: `${user.name}@verdnatura.es`
}, myOptions); }, myOptions);
} }

View File

@ -1,8 +1,11 @@
module.exports = function(Self) { module.exports = function(Self) {
Self.validate('text', isEnabled, {message: 'Description cannot be blank'}); Self.validate('text', function(err) {
function isEnabled(err) {
if (!this.text) err(); if (!this.text) err();
} }, {message: 'Description cannot be blank'});
Self.validate('observationTypeFk', function(err) {
if (!this.observationTypeFk) err();
}, {message: 'type cannot be blank'});
Self.observe('before save', function(ctx, next) { Self.observe('before save', function(ctx, next) {
ctx.instance.created = Date(); ctx.instance.created = Date();

View File

@ -1,10 +1,10 @@
{ {
"name": "ClientObservation", "name": "ClientObservation",
"description": "Client notes", "description": "Client notes",
"base": "VnModel", "base": "VnModel",
"mixins": { "mixins": {
"Loggable": true "Loggable": true
}, },
"options": { "options": {
"mysql": { "mysql": {
"table": "clientObservation" "table": "clientObservation"
@ -26,6 +26,10 @@
"created": { "created": {
"type": "date", "type": "date",
"description": "Creation date and time" "description": "Creation date and time"
},
"observationTypeFk": {
"type": "number",
"description": "Type of observation"
} }
}, },
"relations": { "relations": {
@ -44,14 +48,18 @@
"include": { "include": {
"relation": "worker", "relation": "worker",
"scope": { "scope": {
"fields": ["id"], "fields": [
"id"
],
"include": { "include": {
"relation": "user", "relation": "user",
"scope": { "scope": {
"fields": ["nickname"] "fields": [
"nickname"
]
} }
} }
} }
} }
} }
} }

View File

@ -1,31 +0,0 @@
<vn-crud-model
vn-id="model"
url="clientObservations"
filter="$ctrl.filter"
link="{clientFk: $ctrl.$params.id}"
data="notes"
auto-load="true">
</vn-crud-model>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card class="vn-pa-md">
<div
ng-repeat="note in notes"
class="note vn-pa-sm border-solid border-radius vn-mb-md">
<vn-horizontal class="vn-mb-sm" style="color: #666">
<vn-one>{{::note.worker.user.nickname}}</vn-one>
<vn-auto>{{::note.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
</vn-horizontal>
<vn-horizontal class="text">
{{::note.text}}
</vn-horizontal>
</div>
</vn-card>
</vn-data-viewer>
<a vn-tooltip="New note"
ui-sref="client.card.note.create({id: $ctrl.$params.id})"
vn-bind="+"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -5,9 +5,10 @@ import './style.scss';
export default class Controller extends Section { export default class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.filter = { }
order: 'created DESC', async $onInit() {
}; this.$state.go('home');
window.location.href = await this.vnApp.getUrl(`customer/${this.$params.id}/notes`);
} }
} }

View File

@ -37,7 +37,7 @@ module.exports = Self => {
const tickets = await models.Ticket.find({ const tickets = await models.Ticket.find({
where: {refFk: invoiceOut.ref} where: {refFk: invoiceOut.ref}
}, myOptions); }, myOptions);
const [bookEntry] = await models.Xdiario.find({ const [bookEntry] = await models.Xdiario.find({
where: { where: {
SERIE: invoiceOut.ref[0], SERIE: invoiceOut.ref[0],
@ -55,13 +55,13 @@ module.exports = Self => {
if (bookEntry) { if (bookEntry) {
if (bookEntry.enlazadoSage) { if (bookEntry.enlazadoSage) {
const params = { const params = {
bookEntry: bookEntry.ASIEN, bookEntry: bookEntry.ASIEN,
invoiceOutRef: invoiceOut.ref invoiceOutRef: invoiceOut.ref
} };
await Self.rawSql(`SELECT util.notification_send('book-entry-deleted', ?, NULL)`, await Self.rawSql(`SELECT util.notification_send('book-entry-deleted', ?, NULL)`,
[JSON.stringify(params)], [JSON.stringify(params)],
myOptions); myOptions);
}; }
await models.Xdiario.destroyAll({ await models.Xdiario.destroyAll({
ASIEN: bookEntry.ASIEN ASIEN: bookEntry.ASIEN

View File

@ -48,13 +48,13 @@ module.exports = Self => {
let stmt; let stmt;
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CREATE OR REPLACE TEMPORARY TABLE tmp.ticket `CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
(KEY (ticketFk)) (INDEX (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticket t FROM ticket
WHERE shipped BETWEEN ? AND util.dayEnd(?) WHERE shipped BETWEEN ? AND util.dayEnd(?)
AND refFk IS NULL`, [args.from, args.to])); AND refFk IS NULL`, [args.from, args.to]));
stmts.push(`CALL vn.ticket_getTax(NULL)`); stmts.push(`CALL ticket_getTax(NULL)`);
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CREATE OR REPLACE TEMPORARY TABLE tmp.filter `CREATE OR REPLACE TEMPORARY TABLE tmp.filter
ENGINE = MEMORY ENGINE = MEMORY
@ -71,12 +71,12 @@ module.exports = Self => {
c.isTaxDataChecked, c.isTaxDataChecked,
w.id comercialId, w.id comercialId,
u.name workerName u.name workerName
FROM vn.ticket t FROM ticket t
JOIN vn.company co ON co.id = t.companyFk JOIN company co ON co.id = t.companyFk
JOIN vn.sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN vn.client c ON c.id = t.clientFk JOIN client c ON c.id = t.clientFk
JOIN vn.country cou ON cou.id = c.countryFk JOIN country cou ON cou.id = c.countryFk
LEFT JOIN vn.worker w ON w.id = c.salesPersonFk LEFT JOIN worker w ON w.id = c.salesPersonFk
JOIN account.user u ON u.id = w.id JOIN account.user u ON u.id = w.id
LEFT JOIN ( LEFT JOIN (
SELECT ticketFk, taxableBase SELECT ticketFk, taxableBase

View File

@ -79,6 +79,8 @@ module.exports = Self => {
type type
], ],
myOptions); myOptions);
if (!serial)
throw new UserError('No invoice series found for these parameters');
const invoiceOutSerial = await Self.app.models.InvoiceOutSerial.findById(serial); const invoiceOutSerial = await Self.app.models.InvoiceOutSerial.findById(serial);
if (invoiceOutSerial?.taxAreaFk == 'WORLD') { if (invoiceOutSerial?.taxAreaFk == 'WORLD') {

View File

@ -1,6 +1,6 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('labelPdf', { Self.remoteMethodCtx('labelBarcodePdf', {
description: 'Returns the item label pdf', description: 'Returns the item label pdf with barcode',
accessType: 'READ', accessType: 'READ',
accepts: [ accepts: [
{ {
@ -9,28 +9,24 @@ module.exports = Self => {
required: true, required: true,
description: 'The item id', description: 'The item id',
http: {source: 'path'} http: {source: 'path'}
}, }, {
{
arg: 'recipientId',
type: 'number',
description: 'The recipient id',
required: false
},
{
arg: 'warehouseId', arg: 'warehouseId',
type: 'number', type: 'number',
description: 'The warehouse id',
required: true required: true
}, }, {
{ arg: 'packing',
arg: 'labelNumber',
type: 'number', type: 'number',
required: false required: false
}, }, {
{ arg: 'copies',
arg: 'totalLabels',
type: 'number', type: 'number',
required: false required: false
}, {
arg: 'userId',
type: 'number',
description: 'The user id from accessToken',
http: ctx => ctx.req.accessToken.userId,
required: true
} }
], ],
returns: [ returns: [
@ -49,11 +45,11 @@ module.exports = Self => {
} }
], ],
http: { http: {
path: '/:id/label-pdf', path: '/:id/label-barcode-pdf',
verb: 'GET' verb: 'GET'
}, },
accessScopes: ['DEFAULT', 'read:multimedia'] accessScopes: ['DEFAULT', 'read:multimedia']
}); });
Self.labelPdf = (ctx, id) => Self.printReport(ctx, id, 'item-label'); Self.labelBarcodePdf = (ctx, id) => Self.printReport(ctx, id, 'item-label-barcode');
}; };

View File

@ -0,0 +1,55 @@
module.exports = Self => {
Self.remoteMethodCtx('labelQrPdf', {
description: 'Returns the item label pdf with qr',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'number',
required: true,
description: 'The item id',
http: {source: 'path'}
}, {
arg: 'warehouseId',
type: 'number',
required: true
}, {
arg: 'packing',
type: 'number',
required: false
}, {
arg: 'copies',
type: 'number',
required: false
}, {
arg: 'userId',
type: 'number',
description: 'The user id from accessToken',
http: ctx => ctx.req.accessToken.userId,
required: true
}
],
returns: [
{
arg: 'body',
type: 'file',
root: true
}, {
arg: 'Content-Type',
type: 'String',
http: {target: 'header'}
}, {
arg: 'Content-Disposition',
type: 'String',
http: {target: 'header'}
}
],
http: {
path: '/:id/label-qr-pdf',
verb: 'GET'
},
accessScopes: ['DEFAULT', 'read:multimedia']
});
Self.labelQrPdf = (ctx, id) => Self.printReport(ctx, id, 'item-label-qr');
};

View File

@ -15,7 +15,8 @@ module.exports = Self => {
require('../methods/item/getWasteByItem')(Self); require('../methods/item/getWasteByItem')(Self);
require('../methods/item/createIntrastat')(Self); require('../methods/item/createIntrastat')(Self);
require('../methods/item/buyerWasteEmail')(Self); require('../methods/item/buyerWasteEmail')(Self);
require('../methods/item/labelPdf')(Self); require('../methods/item/labelBarcodePdf')(Self);
require('../methods/item/labelQrPdf')(Self);
require('../methods/item/setVisibleDiscard')(Self); require('../methods/item/setVisibleDiscard')(Self);
require('../methods/item/get')(Self); require('../methods/item/get')(Self);

View File

@ -11,26 +11,26 @@
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<vn-vertical> <vn-vertical>
<vn-textfield <vn-textfield
label="Code" label="Code"
ng-model="$ctrl.itemType.code" ng-model="$ctrl.itemType.code"
rule rule
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
<vn-textfield <vn-textfield
label="Name" label="Name"
ng-model="$ctrl.itemType.name" ng-model="$ctrl.itemType.name"
rule> rule>
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
label="Worker" label="Worker"
ng-model="$ctrl.itemType.workerFk" ng-model="$ctrl.itemType.workerFk"
url="Workers" url="Workers/search"
show-field="firstName" show-field="nickname"
value-field="id" value-field="id"
rule> rule>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
label="Category" label="Category"
ng-model="$ctrl.itemType.categoryFk" ng-model="$ctrl.itemType.categoryFk"
url="ItemCategories" url="ItemCategories"
show-field="name" show-field="name"
@ -38,7 +38,7 @@
rule> rule>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
label="Temperature" label="Temperature"
ng-model="$ctrl.itemType.temperatureFk" ng-model="$ctrl.itemType.temperatureFk"
url="Temperatures" url="Temperatures"
show-field="name" show-field="name"
@ -59,4 +59,4 @@
ng-click="watcher.loadOriginalData()"> ng-click="watcher.loadOriginalData()">
</vn-button> </vn-button>
</vn-button-bar> </vn-button-bar>
</form> </form>

View File

@ -12,26 +12,26 @@
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<vn-vertical> <vn-vertical>
<vn-textfield <vn-textfield
label="Code" label="Code"
ng-model="$ctrl.itemType.code" ng-model="$ctrl.itemType.code"
rule rule
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
<vn-textfield <vn-textfield
label="Name" label="Name"
ng-model="$ctrl.itemType.name" ng-model="$ctrl.itemType.name"
rule> rule>
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
label="Worker" label="Worker"
ng-model="$ctrl.itemType.workerFk" ng-model="$ctrl.itemType.workerFk"
url="Workers" url="Workers/search"
show-field="firstName" show-field="nickname"
value-field="id" value-field="id"
rule> rule>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
label="Category" label="Category"
ng-model="$ctrl.itemType.categoryFk" ng-model="$ctrl.itemType.categoryFk"
url="ItemCategories" url="ItemCategories"
show-field="name" show-field="name"
@ -39,7 +39,7 @@
rule> rule>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
label="Temperature" label="Temperature"
ng-model="$ctrl.itemType.temperatureFk" ng-model="$ctrl.itemType.temperatureFk"
url="Temperatures" url="Temperatures"
show-field="name" show-field="name"

View File

@ -0,0 +1,16 @@
Tickets monitor: Monitor de tickets
Clients on website: Clientes activos en la web
Recent order actions: Acciones recientes en pedidos
Search tickets: Buscar tickets
Delete selected elements: Eliminar los elementos seleccionados
All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
Component lack: Faltan componentes
Ticket too little: Ticket demasiado pequeño
Minimize/Maximize: Minimizar/Maximizar
Problems: Problemas
Theoretical: Teórica
Practical: Práctica
Preparation: Preparación
Auto-refresh: Auto-refresco
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
Is fragile: Es frágil

View File

@ -59,6 +59,9 @@
"isReserve": { "isReserve": {
"type": "boolean", "type": "boolean",
"required": true "required": true
},
"isOnReservationMode": {
"type": "boolean"
} }
} }
} }

View File

@ -29,7 +29,7 @@ module.exports = Self => {
Object.assign(myOptions, options); Object.assign(myOptions, options);
const stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(
`SELECT es.created, u.name, u.id workerFk, est.description state `SELECT es.created, u.name, u.id workerFk, est.description state, es.isScanned
FROM vn.expeditionState es FROM vn.expeditionState es
JOIN vn.expeditionStateType est ON est.id = es.typeFk JOIN vn.expeditionStateType est ON est.id = es.typeFk
JOIN account.user u ON u.id = es.userFk JOIN account.user u ON u.id = es.userFk

View File

@ -31,6 +31,6 @@ module.exports = Self => {
const usesMana = departments.find(department => department.id == workerDepartment.departmentFk); const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
return usesMana ? true : false; return !!usesMana;
}; };
}; };

View File

@ -59,6 +59,11 @@ module.exports = Self => {
arg: 'state', arg: 'state',
type: 'string', type: 'string',
description: `Search request by request state` description: `Search request by request state`
},
{
arg: 'myTeam',
type: 'boolean',
description: `Team partners`
} }
], ],
returns: { returns: {
@ -75,6 +80,8 @@ module.exports = Self => {
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const myOptions = {}; const myOptions = {};
const models = Self.app.models;
const args = ctx.args;
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
@ -82,6 +89,21 @@ module.exports = Self => {
if (ctx.args.mine) if (ctx.args.mine)
ctx.args.attenderFk = userId; ctx.args.attenderFk = userId;
const teamMembersId = [];
if (args.myTeam != null) {
const worker = await models.Worker.findById(userId, {
include: {
relation: 'collegues'
}
}, myOptions);
const collegues = worker.collegues() || [];
for (let collegue of collegues)
teamMembersId.push(collegue.collegueFk);
if (teamMembersId.length == 0)
teamMembersId.push(userId);
}
let where = buildFilter(ctx.args, (param, value) => { let where = buildFilter(ctx.args, (param, value) => {
switch (param) { switch (param) {
case 'search': case 'search':
@ -113,6 +135,11 @@ module.exports = Self => {
return {'w.id': value}; return {'w.id': value};
case 'salesPersonFk': case 'salesPersonFk':
return {'c.salesPersonFk': value}; return {'c.salesPersonFk': value};
case 'myTeam':
if (value)
return {'tr.requesterFk': {inq: teamMembersId}};
else
return {'tr.requesterFk': {nin: teamMembersId}};
} }
}); });

View File

@ -1,11 +1,17 @@
const UserError = require('vn-loopback/util/user-error');
const closure = require('./closure'); const closure = require('./closure');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('closeAll', { Self.remoteMethodCtx('closeAll', {
description: 'Makes the closure process from all warehouses', description: 'Makes the closure process from all warehouses',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [], accepts: [
{
arg: 'options',
type: 'object',
http: {source: 'body'},
description: 'Optional parameters, including transaction.'
}
],
returns: { returns: {
type: 'object', type: 'object',
root: true root: true
@ -16,21 +22,20 @@ module.exports = Self => {
} }
}); });
Self.closeAll = async ctx => { Self.closeAll = async(ctx, options) => {
const userId = ctx.req.accessToken.userId;
const myOptions = {userId};
if (typeof options == 'object')
Object.assign(myOptions, options);
let tx;
// IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts.
const toDate = Date.vnNew(); const toDate = Date.vnNew();
toDate.setHours(0, 0, 0, 0); toDate.setHours(0, 0, 0, 0);
toDate.setDate(toDate.getDate() - 1); toDate.setDate(toDate.getDate() - 1);
const todayMinDate = Date.vnNew();
todayMinDate.setHours(0, 0, 0, 0);
const todayMaxDate = Date.vnNew();
todayMaxDate.setHours(23, 59, 59, 59);
// Prevent closure for current day
if (toDate >= todayMinDate && toDate <= todayMaxDate)
throw new UserError('You cannot close tickets for today');
const tickets = await Self.rawSql(` const tickets = await Self.rawSql(`
SELECT t.id, SELECT t.id,
t.clientFk, t.clientFk,
@ -41,7 +46,7 @@ module.exports = Self => {
c.salesPersonFk, c.salesPersonFk,
c.isToBeMailed, c.isToBeMailed,
c.hasToInvoice, c.hasToInvoice,
co.hasDailyInvoice, c.hasDailyInvoice,
eu.email salesPersonEmail, eu.email salesPersonEmail,
t.addressFk t.addressFk
FROM ticket t FROM ticket t
@ -53,16 +58,17 @@ module.exports = Self => {
JOIN province p ON p.id = c.provinceFk JOIN province p ON p.id = c.provinceFk
JOIN country co ON co.id = p.countryFk JOIN country co ON co.id = p.countryFk
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
JOIN ticketConfig tc ON TRUE
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered')) WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
AND DATE(t.shipped) BETWEEN ? - INTERVAL 7 DAY AND util.dayEnd(?) AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
AND t.refFk IS NULL AND t.refFk IS NULL
GROUP BY t.id GROUP BY t.id
`, [toDate, toDate]); `, [toDate, toDate], myOptions);
const ticketIds = tickets.map(ticket => ticket.id); const ticketIds = tickets.map(ticket => ticket.id);
await Self.rawSql(` await Self.rawSql(`
INSERT INTO util.debug (variable, value) INSERT INTO util.debug (variable, value)
VALUES ('nightInvoicing', ?) VALUES ('nightInvoicing', ?)
`, [ticketIds.join(',')]); `, [ticketIds.join(',')], myOptions);
await Self.rawSql(` await Self.rawSql(`
WITH ticketNotInvoiceable AS( WITH ticketNotInvoiceable AS(
@ -108,6 +114,7 @@ module.exports = Self => {
JOIN alertLevel al ON al.id = ts.alertLevel JOIN alertLevel al ON al.id = ts.alertLevel
JOIN client c ON c.id = t.clientFk JOIN client c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk JOIN province p ON p.id = c.provinceFk
JOIN ticketConfig tc ON TRUE
LEFT JOIN autonomy a ON a.id = p.autonomyFk LEFT JOIN autonomy a ON a.id = p.autonomyFk
JOIN country co ON co.id = p.countryFk JOIN country co ON co.id = p.countryFk
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
@ -116,9 +123,9 @@ module.exports = Self => {
LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD' LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD'
AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple') AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple')
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered')) WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
AND DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?) AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
AND t.refFk IS NULL AND t.refFk IS NULL
AND IFNULL(a.hasDailyInvoice, co.hasDailyInvoice) AND c.hasDailyInvoice
GROUP BY ticketFk GROUP BY ticketFk
HAVING hasErrorToInvoice HAVING hasErrorToInvoice
OR hasErrorTaxDataChecked OR hasErrorTaxDataChecked
@ -131,9 +138,9 @@ module.exports = Self => {
) SELECT IF(errors = '{"tickets": null}', ) SELECT IF(errors = '{"tickets": null}',
'No errors', 'No errors',
util.notification_send('invoice-ticket-closure', errors, NULL)) util.notification_send('invoice-ticket-closure', errors, NULL))
FROM ticketNotInvoiceable`, [toDate, toDate]); FROM ticketNotInvoiceable`, [toDate, toDate], myOptions);
await closure(ctx, Self, tickets); await closure(ctx, Self, tickets, myOptions);
await Self.rawSql(` await Self.rawSql(`
UPDATE ticket t UPDATE ticket t
@ -141,13 +148,17 @@ module.exports = Self => {
JOIN alertLevel al ON al.id = ts.alertLevel JOIN alertLevel al ON al.id = ts.alertLevel
JOIN agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
JOIN ticketConfig tc ON TRUE
LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id
SET t.routeFk = NULL SET t.routeFk = NULL
WHERE DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?) WHERE t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
AND al.code NOT IN ('DELIVERED', 'PACKED') AND al.code NOT IN ('DELIVERED', 'PACKED')
AND NOT t.packages AND NOT t.packages
AND tob.id IS NULL AND tob.id IS NULL
AND t.routeFk`, [toDate, toDate], {userId: ctx.req.accessToken.userId}); AND t.routeFk`, [toDate, toDate], myOptions);
if (tx)
await tx.commit();
return { return {
message: 'Success' message: 'Success'

View File

@ -50,7 +50,7 @@ module.exports = Self => {
c.salesPersonFk, c.salesPersonFk,
c.isToBeMailed, c.isToBeMailed,
c.hasToInvoice, c.hasToInvoice,
co.hasDailyInvoice, c.hasDailyInvoice,
eu.email salesPersonEmail, eu.email salesPersonEmail,
t.addressFk t.addressFk
FROM expedition e FROM expedition e
@ -58,8 +58,6 @@ module.exports = Self => {
JOIN ticketState ts ON ts.ticketFk = t.id JOIN ticketState ts ON ts.ticketFk = t.id
JOIN alertLevel al ON al.id = ts.alertLevel JOIN alertLevel al ON al.id = ts.alertLevel
JOIN client c ON c.id = t.clientFk JOIN client c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk
JOIN country co ON co.id = p.countryFk
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
WHERE al.code = 'PACKED' WHERE al.code = 'PACKED'
AND t.id = ? AND t.id = ?

View File

@ -12,19 +12,21 @@ module.exports = async function(ctx, Self, tickets, options) {
Object.assign(myOptions, options); Object.assign(myOptions, options);
let tx; let tx;
// if (!myOptions.transaction) { // IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts.
// tx = await Self.beginTransaction({});
// myOptions.transaction = tx;
// }
if (tickets.length == 0) return; if (tickets.length == 0) return;
const failedtickets = []; const failedtickets = [];
for (const ticket of tickets) { for (const ticket of tickets) {
try { try {
await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], {userId}); await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], myOptions);
await Self.app.models.InvoiceOut.getSerial(ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick'); await Self.app.models.InvoiceOut.getSerial(
ticket.clientFk,
ticket.companyFk,
ticket.addressFk,
'quick',
myOptions);
await Self.rawSql( await Self.rawSql(
`CALL vn.ticket_closeByTicket(?)`, `CALL vn.ticket_closeByTicket(?)`,
[ticket.id], [ticket.id],

Some files were not shown because too many files have changed in this diff Show More