Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4859-export_db
This commit is contained in:
commit
67cf4ebbea
|
@ -51,7 +51,7 @@ module.exports = Self => {
|
|||
const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file);
|
||||
await fs.unlink(dstFile);
|
||||
} catch (err) {
|
||||
if (err.code != 'ENOENT')
|
||||
if (err.code != 'ENOENT' && dms.file)
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
|
|
@ -2569,10 +2569,6 @@ UPDATE `vn`.`route`
|
|||
UPDATE `vn`.`route`
|
||||
SET `invoiceInFk`=2
|
||||
WHERE `id`=2;
|
||||
INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`)
|
||||
VALUES
|
||||
(18, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE())),
|
||||
(19, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE()));
|
||||
|
||||
INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`)
|
||||
VALUES
|
||||
|
|
|
@ -37,7 +37,7 @@ export default class Controller extends Section {
|
|||
|
||||
const validations = window.validations;
|
||||
value.forEach(log => {
|
||||
const locale = validations[log.changedModel].locale ? validations[log.changedModel].locale : {};
|
||||
const locale = validations[log.changedModel] && validations[log.changedModel].locale ? validations[log.changedModel].locale : {};
|
||||
|
||||
log.oldProperties = this.getInstance(log.oldInstance, locale);
|
||||
log.newProperties = this.getInstance(log.newInstance, locale);
|
||||
|
|
|
@ -91,7 +91,18 @@ module.exports = Self => {
|
|||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {'c.id': {inq: value}}
|
||||
: {'c.name': {like: `%${value}%`}};
|
||||
: {or: [
|
||||
{'c.name': {like: `%${value}%`}},
|
||||
{'c.socialName': {like: `%${value}%`}},
|
||||
]};
|
||||
case 'phone':
|
||||
return {or: [
|
||||
{'c.phone': {like: `%${value}%`}},
|
||||
{'c.mobile': {like: `%${value}%`}},
|
||||
]};
|
||||
case 'zoneFk':
|
||||
param = 'a.postalCode';
|
||||
return {[param]: {inq: postalCode}};
|
||||
case 'name':
|
||||
case 'salesPersonFk':
|
||||
case 'fi':
|
||||
|
@ -100,12 +111,8 @@ module.exports = Self => {
|
|||
case 'postcode':
|
||||
case 'provinceFk':
|
||||
case 'email':
|
||||
case 'phone':
|
||||
param = `c.${param}`;
|
||||
return {[param]: value};
|
||||
case 'zoneFk':
|
||||
param = 'a.postalCode';
|
||||
return {[param]: {inq: postalCode}};
|
||||
return {[param]: {like: `%${value}%`}};
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -119,6 +126,7 @@ module.exports = Self => {
|
|||
c.fi,
|
||||
c.socialName,
|
||||
c.phone,
|
||||
c.mobile,
|
||||
c.city,
|
||||
c.postcode,
|
||||
c.email,
|
||||
|
|
|
@ -51,14 +51,14 @@ module.exports = Self => {
|
|||
u.nickname AS userNickname,
|
||||
vn.ticketTotalVolume(t.id) AS volume,
|
||||
tob.description
|
||||
FROM route r
|
||||
FROM vn.route r
|
||||
JOIN ticket t ON t.routeFk = r.id
|
||||
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
|
||||
LEFT JOIN state st ON st.id = ts.stateFk
|
||||
LEFT JOIN warehouse wh ON wh.id = t.warehouseFk
|
||||
LEFT JOIN observationType ot ON ot.code = 'delivery'
|
||||
LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id
|
||||
LEFT JOIN observationType ot ON tob.observationTypeFk = ot.id
|
||||
AND ot.code = 'delivery'
|
||||
AND tob.observationTypeFk = ot.id
|
||||
LEFT JOIN address a ON a.id = t.addressFk
|
||||
LEFT JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||
LEFT JOIN account.user u ON u.id = r.workerFk
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
const Imap = require('imap');
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('checkInbox', {
|
||||
description: 'Check an email inbox and process it',
|
||||
accessType: 'READ',
|
||||
returns:
|
||||
{
|
||||
arg: 'body',
|
||||
type: 'file',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/checkInbox`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.checkInbox = async() => {
|
||||
let imapConfig = await Self.app.models.WorkerTimeControlParams.findOne();
|
||||
let imap = new Imap({
|
||||
user: imapConfig.mailUser,
|
||||
password: imapConfig.mailPass,
|
||||
host: imapConfig.mailHost,
|
||||
port: 993,
|
||||
tls: true
|
||||
});
|
||||
let isEmailOk;
|
||||
let uid;
|
||||
let emailBody;
|
||||
|
||||
function openInbox(cb) {
|
||||
imap.openBox('INBOX', true, cb);
|
||||
}
|
||||
|
||||
imap.once('ready', function() {
|
||||
openInbox(function(err, box) {
|
||||
if (err) throw err;
|
||||
const totalMessages = box.messages.total;
|
||||
if (totalMessages == 0)
|
||||
imap.end();
|
||||
|
||||
let f = imap.seq.fetch('1:*', {
|
||||
bodies: ['HEADER.FIELDS (FROM SUBJECT)', '1'],
|
||||
struct: true
|
||||
});
|
||||
f.on('message', function(msg, seqno) {
|
||||
isEmailOk = false;
|
||||
msg.on('body', function(stream, info) {
|
||||
let buffer = '';
|
||||
let bufferCopy = '';
|
||||
stream.on('data', function(chunk) {
|
||||
buffer = chunk.toString('utf8');
|
||||
if (info.which === '1' && bufferCopy.length == 0)
|
||||
bufferCopy = buffer.replace(/\s/g, ' ');
|
||||
});
|
||||
stream.on('end', function() {
|
||||
if (bufferCopy.length > 0) {
|
||||
emailBody = bufferCopy.toUpperCase().trim();
|
||||
|
||||
const bodyPositionOK = emailBody.match(/\bOK\b/i);
|
||||
if (bodyPositionOK != null && (bodyPositionOK.index == 0 || bodyPositionOK.index == 122))
|
||||
isEmailOk = true;
|
||||
else
|
||||
isEmailOk = false;
|
||||
}
|
||||
});
|
||||
msg.once('attributes', function(attrs) {
|
||||
uid = attrs.uid;
|
||||
});
|
||||
msg.once('end', function() {
|
||||
if (info.which === 'HEADER.FIELDS (FROM SUBJECT)') {
|
||||
if (isEmailOk) {
|
||||
imap.move(uid, 'exito', function(err) {
|
||||
});
|
||||
emailConfirm(buffer);
|
||||
} else {
|
||||
imap.move(uid, 'error', function(err) {
|
||||
});
|
||||
emailReply(buffer, emailBody);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
f.once('end', function() {
|
||||
imap.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
imap.connect();
|
||||
return 'Leer emails de gestion horaria';
|
||||
};
|
||||
|
||||
async function emailConfirm(buffer) {
|
||||
const now = new Date();
|
||||
const from = JSON.stringify(Imap.parseHeader(buffer).from);
|
||||
const subject = JSON.stringify(Imap.parseHeader(buffer).subject);
|
||||
|
||||
const timeControlDate = await getEmailDate(subject);
|
||||
const week = timeControlDate[0];
|
||||
const year = timeControlDate[1];
|
||||
const user = await getUser(from);
|
||||
let workerMail;
|
||||
|
||||
if (user.id != null) {
|
||||
workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
|
||||
where: {
|
||||
week: week,
|
||||
year: year,
|
||||
workerFk: user.id
|
||||
}
|
||||
});
|
||||
}
|
||||
if (workerMail != null) {
|
||||
await workerMail.updateAttributes({
|
||||
updated: now,
|
||||
state: 'CONFIRMED'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function emailReply(buffer, emailBody) {
|
||||
const now = new Date();
|
||||
const from = JSON.stringify(Imap.parseHeader(buffer).from);
|
||||
const subject = JSON.stringify(Imap.parseHeader(buffer).subject);
|
||||
|
||||
const timeControlDate = await getEmailDate(subject);
|
||||
const week = timeControlDate[0];
|
||||
const year = timeControlDate[1];
|
||||
const user = await getUser(from);
|
||||
let workerMail;
|
||||
|
||||
if (user.id != null) {
|
||||
workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
|
||||
where: {
|
||||
week: week,
|
||||
year: year,
|
||||
workerFk: user.id
|
||||
}
|
||||
});
|
||||
|
||||
if (workerMail != null) {
|
||||
await workerMail.updateAttributes({
|
||||
updated: now,
|
||||
state: 'REVISE',
|
||||
reason: emailBody
|
||||
});
|
||||
} else
|
||||
await sendMail(user, subject, emailBody);
|
||||
}
|
||||
}
|
||||
|
||||
async function getUser(workerEmail) {
|
||||
const userEmail = workerEmail.match(/(?<=<)(.*?)(?=>)/);
|
||||
|
||||
let [user] = await Self.rawSql(`SELECT u.id,u.name FROM account.user u
|
||||
LEFT JOIN account.mailForward m on m.account = u.id
|
||||
WHERE forwardTo =? OR
|
||||
CONCAT(u.name,'@verdnatura.es') = ?`,
|
||||
[userEmail[0], userEmail[0]]);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async function getEmailDate(subject) {
|
||||
const date = subject.match(/\d+/g);
|
||||
return date;
|
||||
}
|
||||
|
||||
async function sendMail(user, subject, emailBody) {
|
||||
const sendTo = 'rrhh@verdnatura.es';
|
||||
const emailSubject = subject + ' ' + user.name;
|
||||
|
||||
await Self.app.models.Mail.create({
|
||||
receiver: sendTo,
|
||||
subject: emailSubject,
|
||||
body: emailBody
|
||||
});
|
||||
}
|
||||
};
|
|
@ -332,18 +332,9 @@ module.exports = Self => {
|
|||
}, myOptions);
|
||||
|
||||
const timestamp = started.getTime() / 1000;
|
||||
await models.Mail.create({
|
||||
receiver: previousReceiver,
|
||||
subject: $t('Record of hours week', {
|
||||
week: args.week,
|
||||
year: args.year
|
||||
}),
|
||||
body: `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}`
|
||||
}, myOptions);
|
||||
const url = `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}`;
|
||||
|
||||
query = `INSERT IGNORE INTO workerTimeControlMail (workerFk, year, week)
|
||||
VALUES (?, ?, ?);`;
|
||||
await Self.rawSql(query, [previousWorkerFk, args.year, args.week], myOptions);
|
||||
await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, previousReceiver, args.week, args.year, url);
|
||||
|
||||
previousWorkerFk = day.workerFk;
|
||||
previousReceiver = day.receiver;
|
||||
|
|
|
@ -2,15 +2,12 @@ const models = require('vn-loopback/server/server').models;
|
|||
|
||||
describe('workerTimeControl sendMail()', () => {
|
||||
const workerId = 18;
|
||||
const ctx = {
|
||||
req: {
|
||||
__: value => {
|
||||
return value;
|
||||
const activeCtx = {
|
||||
getLocale: () => {
|
||||
return 'en';
|
||||
}
|
||||
},
|
||||
args: {}
|
||||
|
||||
};
|
||||
const ctx = {req: activeCtx, args: {}};
|
||||
|
||||
it('should fill time control of a worker without records in Journey and with rest', async() => {
|
||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
const {Email} = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('weeklyHourRecordEmail', {
|
||||
description: 'Sends the buyer waste email',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'recipient',
|
||||
type: 'string',
|
||||
description: 'The recipient email',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
arg: 'week',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
arg: 'year',
|
||||
type: 'number',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'url',
|
||||
type: 'string',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: '/weekly-hour-hecord-email',
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.weeklyHourRecordEmail = async(ctx, recipient, week, year, url) => {
|
||||
const params = {
|
||||
recipient: recipient,
|
||||
lang: ctx.req.getLocale(),
|
||||
week: week,
|
||||
year: year,
|
||||
url: url
|
||||
};
|
||||
|
||||
const email = new Email('weekly-hour-record', params);
|
||||
|
||||
return email.send();
|
||||
};
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/worker-time-control-mail/checkInbox')(Self);
|
||||
};
|
|
@ -7,6 +7,7 @@ module.exports = Self => {
|
|||
require('../methods/worker-time-control/updateTimeEntry')(Self);
|
||||
require('../methods/worker-time-control/sendMail')(Self);
|
||||
require('../methods/worker-time-control/updateWorkerTimeControlMail')(Self);
|
||||
require('../methods/worker-time-control/weeklyHourRecordEmail')(Self);
|
||||
|
||||
Self.rewriteDbError(function(err) {
|
||||
if (err.code === 'ER_DUP_ENTRY')
|
||||
|
|
|
@ -50,3 +50,9 @@
|
|||
.page-break-after {
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.ellipsize {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
const Stylesheet = require(`vn-print/core/stylesheet`);
|
||||
|
||||
const path = require('path');
|
||||
const vnPrintPath = path.resolve('print');
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${vnPrintPath}/common/css/spacing.css`,
|
||||
`${vnPrintPath}/common/css/misc.css`,
|
||||
`${vnPrintPath}/common/css/layout.css`,
|
||||
`${vnPrintPath}/common/css/email.css`])
|
||||
.mergeStyles();
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
subject: Weekly time log
|
||||
title: Record of hours week {0} year {1}
|
||||
dear: Dear worker
|
||||
description: Access the following link:<br/><br/>
|
||||
{0} <br/><br/>
|
||||
Click 'SATISFIED' if you agree with the hours worked. Otherwise, press 'NOT SATISFIED', detailing the cause of the disagreement.
|
|
@ -0,0 +1,6 @@
|
|||
subject: Registro de horas semanal
|
||||
title: Registro de horas semana {0} año {1}
|
||||
dear: Estimado trabajador
|
||||
description: Acceda al siguiente enlace:<br/><br/>
|
||||
{0} <br/><br/>
|
||||
Pulse 'CONFORME' si esta de acuerdo con las horas trabajadas. En caso contrario pulse 'NO CONFORME', detallando la causa de la disconformidad.
|
|
@ -0,0 +1,9 @@
|
|||
<email-body v-bind="$props">
|
||||
<div class="grid-row">
|
||||
<div class="grid-block vn-pa-ml">
|
||||
<h1>{{ $t('title', [week, year]) }}</h1>
|
||||
<p>{{$t('dear')}},</p>
|
||||
<p v-html="$t('description', [url])"></p>
|
||||
</div>
|
||||
</div>
|
||||
</email-body>
|
|
@ -0,0 +1,23 @@
|
|||
const Component = require(`vn-print/core/component`);
|
||||
const emailBody = new Component('email-body');
|
||||
|
||||
module.exports = {
|
||||
name: 'weekly-hour-record',
|
||||
components: {
|
||||
'email-body': emailBody.build()
|
||||
},
|
||||
props: {
|
||||
week: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
year: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
html {
|
||||
font-family: "Roboto";
|
||||
margin-top: -7px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
@ -9,7 +9,7 @@ html {
|
|||
}
|
||||
#vertical {
|
||||
writing-mode: vertical-rl;
|
||||
height: 226px;
|
||||
height: 240px;
|
||||
margin-left: -13px;
|
||||
}
|
||||
.outline {
|
||||
|
@ -18,6 +18,7 @@ html {
|
|||
}
|
||||
#nickname {
|
||||
font-size: 22px;
|
||||
max-width: 50px;
|
||||
}
|
||||
#agencyDescripton {
|
||||
font-size: 32px;
|
||||
|
|
|
@ -1,35 +1,36 @@
|
|||
<report-body v-bind="$props">
|
||||
<template v-slot:header>
|
||||
<span></span>
|
||||
</template>
|
||||
<table v-for="labelData in labelsData">
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<table v-for="labelData in labelsData" style="break-before: page">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="6"><span id="vertical">{{labelData.levelV}}</span></td>
|
||||
<td id="ticketFk">{{labelData.ticketFk}} ⬸ {{labelData.clientFk}}</td>
|
||||
<td colspan="2" id="shipped">{{labelData.shipped}}</td>
|
||||
<td rowspan="6"><span id="vertical" class="ellipsize">
|
||||
{{labelData.collectionFk ? `${labelData.collectionFk} ~ ${labelData.wagon}-${labelData.level}` : '-'.repeat(23)}}
|
||||
</span></td>
|
||||
<td id="ticketFk">
|
||||
{{labelData.clientFk ? `${labelData.ticketFk} « ${labelData.clientFk}` : labelData.ticketFk}}
|
||||
</td>
|
||||
<td colspan="2" id="shipped">{{labelData.shipped ? labelData.shipped : '---'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="3"><div v-html="getBarcode(labelData.ticketFk)" id="barcode"></div></td>
|
||||
<td class="outline">{{labelData.workerCode}}</td>
|
||||
<td class="outline">{{labelData.workerCode ? labelData.workerCode : '---'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="outline">{{labelData.labelCount}}</td>
|
||||
<td class="outline">{{labelData.labelCount ? labelData.labelCount : 0}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="outline">{{labelData.size}}</td>
|
||||
<td class="outline">{{labelData.code == 'plant' ? labelData.size + 'cm' : labelData.volume + 'm³'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="agencyDescripton">{{labelData.agencyDescription}}</div></td>
|
||||
<td id="bold">{{labelData.lineCount}}</td>
|
||||
<td><div id="agencyDescripton" class="ellipsize">{{labelData.agencyDescription}}</div></td>
|
||||
<td id="bold">{{labelData.lineCount ? labelData.lineCount : 0}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="nickname">{{labelData.nickName}}</td>
|
||||
<td id="bold">{{labelData.agencyHour}}</td>
|
||||
<td id="nickname" class="ellipsize">{{labelData.nickName ? labelData.nickName : '---'}}</td>
|
||||
<td id="bold">{{labelData.shipped ? labelData.shippedHour : labelData.zoneHour}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<template v-slot:footer>
|
||||
<span></span>
|
||||
</template>
|
||||
</report-body>
|
||||
</body>
|
||||
</html>
|
|
@ -40,7 +40,7 @@ module.exports = {
|
|||
format: 'code128',
|
||||
displayValue: false,
|
||||
width: 3.8,
|
||||
height: 110,
|
||||
height: 115,
|
||||
});
|
||||
return xmlSerializer.serializeToString(svgNode);
|
||||
},
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
"width": "10.4cm",
|
||||
"height": "4.8cm",
|
||||
"margin": {
|
||||
"top": "0cm",
|
||||
"right": "0.5cm",
|
||||
"top": "0.3cm",
|
||||
"right": "0.6cm",
|
||||
"bottom": "0cm",
|
||||
"left": "0cm"
|
||||
},
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
SELECT c.itemPackingTypeFk,
|
||||
CONCAT(tc.collectionFk, ' ', LEFT(cc.code, 4)) color,
|
||||
CONCAT(tc.collectionFk, ' ', SUBSTRING('ABCDEFGH',tc.wagon, 1), '-', tc.`level`) levelV,
|
||||
tc.ticketFk,
|
||||
LEFT(COALESCE(et.description, zo.name, am.name),12) agencyDescription,
|
||||
SELECT tc.collectionFk,
|
||||
SUBSTRING('ABCDEFGH', tc.wagon, 1) wagon,
|
||||
tc.`level`,
|
||||
t.id ticketFk,
|
||||
COALESCE(et.description, zo.name, am.name) agencyDescription,
|
||||
am.name,
|
||||
t.clientFk,
|
||||
CONCAT(CAST(SUM(sv.volume) AS DECIMAL(5, 2)), 'm³') m3 ,
|
||||
CAST(IF(ic.code = 'plant', CONCAT(MAX(i.`size`),' cm'), COUNT(*)) AS CHAR) size,
|
||||
CAST(SUM(sv.volume) AS DECIMAL(5, 2)) volume,
|
||||
MAX(i.`size`) `size`,
|
||||
ic.code,
|
||||
w.code workerCode,
|
||||
tt.labelCount,
|
||||
IF(HOUR(t.shipped), TIME_FORMAT(t.shipped, '%H:%i'), TIME_FORMAT(zo.`hour`, '%H:%i')) agencyHour,
|
||||
TIME_FORMAT(t.shipped, '%H:%i') shippedHour,
|
||||
TIME_FORMAT(zo.`hour`, '%H:%i') zoneHour,
|
||||
DATE_FORMAT(t.shipped, '%d/%m/%y') shipped,
|
||||
COUNT(*) lineCount,
|
||||
t.nickName
|
||||
t.nickName,
|
||||
tt.labelCount,
|
||||
COUNT(*) lineCount
|
||||
FROM vn.ticket t
|
||||
JOIN vn.ticketCollection tc ON tc.ticketFk = t.id
|
||||
JOIN vn.collection c ON c.id = tc.collectionFk
|
||||
LEFT JOIN vn.ticketCollection tc ON tc.ticketFk = t.id
|
||||
LEFT JOIN vn.collection c ON c.id = tc.collectionFk
|
||||
LEFT JOIN vn.collectionColors cc ON cc.shelve = tc.`level`
|
||||
AND cc.wagon = tc.wagon
|
||||
AND cc.trainFk = c.trainFk
|
||||
|
@ -24,12 +26,12 @@ SELECT c.itemPackingTypeFk,
|
|||
JOIN vn.item i ON i.id = s.itemFk
|
||||
JOIN vn.itemType it ON it.id = i.typeFk
|
||||
JOIN vn.itemCategory ic ON ic.id = it.categoryFk
|
||||
JOIN vn.worker w ON w.id = c.workerFk
|
||||
LEFT JOIN vn.worker w ON w.id = c.workerFk
|
||||
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
|
||||
LEFT JOIN vn.ticketTrolley tt ON tt.ticket = t.id
|
||||
LEFT JOIN vn.`zone` zo ON t.zoneFk = zo.id
|
||||
LEFT JOIN vn.routesMonitor rm ON rm.routeFk = t.routeFk
|
||||
LEFT JOIN vn.expeditionTruck et ON et.id = rm.expeditionTruckFk
|
||||
WHERE tc.ticketFk IN (?)
|
||||
WHERE t.id IN (?)
|
||||
GROUP BY t.id
|
||||
ORDER BY cc.`code`;
|
Loading…
Reference in New Issue