Merge branch 'dev' into 6067-vnUser_privileges_and_verifyEmail
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2023-10-19 08:50:29 +00:00
commit 3294937b54
13 changed files with 281 additions and 84 deletions

View File

@ -20,10 +20,6 @@
"username": {
"type": "string"
},
"password": {
"type": "string",
"required": true
},
"roleFk": {
"type": "number",
"mysql": {
@ -39,9 +35,6 @@
"active": {
"type": "boolean"
},
"email": {
"type": "string"
},
"created": {
"type": "date"
},

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('WorkerDepartment', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,15 +1,24 @@
const models = require('vn-loopback/server/server').models;
describe('Client transactions', () => {
const ctx = {};
it('should call transactions() method to receive a list of Web Payments from BRUCE WAYNE', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {};
const filter = {where: {clientFk: 1101}};
const result = await models.Client.transactions(ctx, filter, options);
const result = await models.Client.transactions(
ctx,
filter,
undefined,
undefined,
undefined,
undefined,
undefined,
options
);
expect(result[1].id).toBeTruthy();
@ -26,9 +35,17 @@ describe('Client transactions', () => {
try {
const options = {transaction: tx};
const ctx = {args: {orderFk: 6}};
const filter = {};
const result = await models.Client.transactions(ctx, filter, options);
const result = await models.Client.transactions(
ctx,
filter,
6,
undefined,
undefined,
undefined,
undefined,
options
);
const firstRow = result[0];
@ -47,10 +64,17 @@ describe('Client transactions', () => {
try {
const options = {transaction: tx};
const ctx = {args: {amount: 40}};
const filter = {};
const result = await models.Client.transactions(ctx, filter, options);
const result = await models.Client.transactions(
ctx,
filter,
undefined,
undefined,
40,
undefined,
undefined,
options
);
const randomIndex = Math.floor(Math.random() * result.length);
const transaction = result[randomIndex];
@ -63,4 +87,43 @@ describe('Client transactions', () => {
throw e;
}
});
it('should call transactions() method filtering by date', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {};
const withResults = await models.Client.transactions(
ctx,
filter,
undefined,
undefined,
undefined,
'2000/12/31',
undefined,
options
);
expect(withResults.length).toEqual(6);
const noResults = await models.Client.transactions(
ctx,
filter,
undefined,
undefined,
undefined,
'2099/12/31',
undefined,
options
);
expect(noResults.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -12,22 +12,26 @@ module.exports = Self => {
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
},
{
arg: 'orderFk',
type: 'number',
http: {source: 'query'}
},
{
arg: 'clientFk',
type: 'number',
http: {source: 'query'}
},
{
arg: 'amount',
type: 'number',
http: {source: 'query'}
},
{
arg: 'from',
type: 'date',
},
{
arg: 'to',
type: 'date',
}
],
returns: {
@ -40,14 +44,15 @@ module.exports = Self => {
}
});
Self.transactions = async(ctx, filter, options) => {
const args = ctx.args;
Self.transactions = async(ctx, filter, orderFk, clientFk, amount, from, to, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const where = buildFilter(args, (param, value) => {
if (to) to.setHours(23, 59, 59, 999);
const where = buildFilter({orderFk, clientFk, amount, from, to}, (param, value) => {
switch (param) {
case 'orderFk':
return {'t.id': value};
@ -55,6 +60,10 @@ module.exports = Self => {
return {'t.clientFk': value};
case 'amount':
return {'t.amount': (value * 100)};
case 'from':
return {'t.created': {gte: value}};
case 'to':
return {'t.created': {lte: value}};
}
});

View File

@ -138,14 +138,15 @@ module.exports = Self => {
// Update original sale
const rest = originalSale.quantity - sale.quantity;
query = `UPDATE sale
SET quantity = ?
SET quantity = ?,
originalQuantity = ?
WHERE id = ?`;
await Self.rawSql(query, [rest, sale.id], options);
await Self.rawSql(query, [rest, rest, sale.id], options);
// Clone sale with new quantity
query = `INSERT INTO sale (itemFk, ticketFk, concept, quantity, originalQuantity, price, discount, priceFixed,
query = `INSERT INTO sale (itemFk, ticketFk, concept, quantity, price, discount, priceFixed,
reserved, isPicked, isPriceFixed, isAdded)
SELECT itemFk, ?, concept, ?, originalQuantity, price, discount, priceFixed,
SELECT itemFk, ?, concept, ?, price, discount, priceFixed,
reserved, isPicked, isPriceFixed, isAdded
FROM sale
WHERE id = ?`;

View File

@ -201,7 +201,7 @@ class Controller extends Section {
sendImportSms() {
const params = {
ticketId: this.id,
created: this.ticket.updated
shipped: this.ticket.shipped
};
this.showSMSDialog({
message: this.$t('Minimum is needed', params)

View File

@ -1,3 +1,3 @@
Make a payment: "Verdnatura communicates:\rYour order is pending of payment.\rPlease, enter the web page and make the payment with card.\rThank you."
Minimum is needed: "Verdnatura communicates:\rA minimum import of 50€ (Without BAT) is needed for your order {{ticketId}} from date {{created | date: 'dd/MM/yyyy'}} to receive it with no extra fees."
Minimum is needed: "Verdnatura communicates:\rA minimum import of 50€ (Without BAT) is needed for your order {{ticketId}} from date {{shipped | date: 'dd/MM/yyyy'}} to receive it with no extra fees."
Send changes: "Verdnatura communicates:\rOrder {{ticketId}} date {{created | date: 'dd/MM/yyyy'}}\r{{changes}}"

View File

@ -4,7 +4,7 @@ Show pallet report: Ver hoja de pallet
Change shipped hour: Cambiar hora de envío
Shipped hour: Hora de envío
Make a payment: "Verdnatura le comunica:\rSu pedido está pendiente de pago.\rPor favor, entre en la página web y efectúe el pago con tarjeta.\rMuchas gracias."
Minimum is needed: "Verdnatura le recuerda:\rEs necesario un importe mínimo de 50€ (Sin IVA) en su pedido {{ticketId}} del día {{created | date: 'dd/MM/yyyy'}} para recibirlo sin portes adicionales."
Minimum is needed: "Verdnatura le recuerda:\rEs necesario un importe mínimo de 50€ (Sin IVA) en su pedido {{ticketId}} del día {{shipped | date: 'dd/MM/yyyy'}} para recibirlo sin portes adicionales."
Ticket invoiced: Ticket facturado
Make invoice: Crear factura
Regenerate invoice PDF: Regenerar PDF factura

View File

@ -0,0 +1,103 @@
const models = require('vn-loopback/server/server').models;
describe('updateWorkerTimeControlMail()', () => {
it('should update WorkerTimeControlMail if exist record', async() => {
const tx = await models.WorkerTimeControlMail.beginTransaction({});
const args = {
workerId: 9,
week: 50,
year: 2000,
state: 'CONFIRMED'
};
const ctx = {args};
try {
const options = {transaction: tx};
const beforeMail = await models.WorkerTimeControlMail.findOne({
where: {
workerFk: args.workerId,
year: args.year,
week: args.week,
}
}, options);
await models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, options);
const afterMail = await models.WorkerTimeControlMail.findOne({
where: {
workerFk: args.workerId,
year: args.year,
week: args.week,
}
}, options);
expect(beforeMail.state).toEqual('SENDED');
expect(afterMail.state).toEqual(args.state);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should insert WorkerTimeControlMail if exist record', async() => {
const tx = await models.WorkerTimeControlMail.beginTransaction({});
const args = {
workerId: 1,
week: 51,
year: 2000,
state: 'SENDED'
};
const ctx = {args};
try {
const options = {transaction: tx};
const beforeMail = await models.WorkerTimeControlMail.find({
where: {
workerFk: args.workerId,
year: args.year,
week: args.week,
}
}, options);
await models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, options);
const afterMail = await models.WorkerTimeControlMail.find({
where: {
workerFk: args.workerId,
year: args.year,
week: args.week,
}
}, options);
expect(beforeMail).toEqual([]);
expect(afterMail.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should throw error if not exist any record in this week', async() => {
const tx = await models.WorkerTimeControlMail.beginTransaction({});
const ctx = {args: {
workerId: 1,
week: 1,
year: 0,
state: 'SENDED'
}};
let error;
try {
const options = {transaction: tx};
await models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual(`There aren't records for this week`);
});
});

View File

@ -40,30 +40,39 @@ module.exports = Self => {
Self.updateWorkerTimeControlMail = async(ctx, options) => {
const models = Self.app.models;
const args = ctx.args;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const workerTimeControlMail = await models.WorkerTimeControlMail.findOne({
const [sent] = await models.WorkerTimeControlMail.find({
where: {
workerFk: args.workerId,
year: args.year,
week: args.week
}
week: args.week,
},
limit: 1
}, myOptions);
if (!workerTimeControlMail) throw new UserError(`There aren't records for this week`);
if (!sent) throw new UserError(`There aren't records for this week`);
await workerTimeControlMail.updateAttributes({
state: args.state,
reason: args.reason || null
}, myOptions);
const workerTimeControlMail = await models.WorkerTimeControlMail.upsertWithWhere(
{
year: args.year,
week: args.week,
workerFk: args.workerId
},
{
state: args.state,
reason: args.workerId,
year: args.year,
week: args.week,
workerFk: args.workerId
},
myOptions);
if (args.state == 'SENDED') {
await workerTimeControlMail.updateAttributes({
sendedCounter: workerTimeControlMail.sendedCounter + 1
sendedCounter: workerTimeControlMail.sendedCounter ? workerTimeControlMail.sendedCounter + 1 : 1
}, myOptions);
}
};

View File

@ -61,9 +61,8 @@ module.exports = Self => {
const url = `${salix.url}worker/${args.workerId}/time-control?timestamp=${timestamp}`;
ctx.args.url = url;
await Self.sendTemplate(ctx, 'weekly-hour-record');
return models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, myOptions);
await models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, myOptions);
return Self.sendTemplate(ctx, 'weekly-hour-record');
};
function getMondayDateFromYearWeek(yearNumber, weekNumber) {

View File

@ -79,30 +79,32 @@
</vn-table>
</vn-card>
<vn-button-bar ng-show="$ctrl.state" class="vn-w-lg">
<vn-button-bar class="vn-w-lg">
<div ng-show="$ctrl.state">
<vn-button
label="Satisfied"
disabled="$ctrl.state == 'CONFIRMED'"
ng-show="$ctrl.isHimSelf"
ng-click="$ctrl.isSatisfied()">
</vn-button>
<vn-button
label="Not satisfied"
disabled="$ctrl.state == 'REVISE'"
ng-show="$ctrl.isHimSelf"
ng-click="reason.show()">
</vn-button>
<vn-button
label="Reason"
ng-show="$ctrl.reason && ($ctrl.isHimSelf || $ctrl.isHr)"
ng-click="reason.show()">
</vn-button>
</div>
<vn-button
label="Satisfied"
disabled="$ctrl.state == 'CONFIRMED'"
ng-if="$ctrl.isHimSelf"
ng-click="$ctrl.isSatisfied()">
</vn-button>
<vn-button
label="Not satisfied"
disabled="$ctrl.state == 'REVISE'"
ng-if="$ctrl.isHimSelf"
ng-click="reason.show()">
</vn-button>
<vn-button
label="Reason"
ng-if="$ctrl.reason && ($ctrl.isHimSelf || $ctrl.isHr)"
ng-click="reason.show()">
</vn-button>
<vn-button
label="Resend"
label="{{$ctrl.state ? 'Resend' : 'Send'}}"
ng-click="sendEmailConfirmation.show()"
class="right"
vn-tooltip="Resend email of this week to the user"
ng-show="::$ctrl.isHr">
vn-tooltip="{{$ctrl.state ? 'Resend' : 'Send'}} email of this week to the user"
ng-if="$ctrl.isHr && $ctrl.state != 'CONFIRMED' && $ctrl.canResend">
</vn-button>
</vn-button-bar>
</div>

View File

@ -53,6 +53,8 @@ class Controller extends Section {
set worker(value) {
this._worker = value;
this.fetchHours();
if (this.date)
this.getWeekData();
}
/**
@ -110,7 +112,8 @@ class Controller extends Section {
}
if (!this.weekTotalHours) this.fetchHours();
this.getWeekData();
if (this.worker)
this.getWeekData();
}
set weekTotalHours(totalHours) {
@ -127,17 +130,34 @@ class Controller extends Section {
workerFk: this.$params.id,
year: this._date.getFullYear(),
week: this.getWeekNumber(this._date)
}
},
};
this.$http.get('WorkerTimeControlMails', {filter})
.then(res => {
const mail = res.data;
if (!mail.length) {
if (!res.data.length) {
this.state = null;
return;
}
this.state = mail[0].state;
this.reason = mail[0].reason;
const [mail] = res.data;
this.state = mail.state;
this.reason = mail.reason;
});
this.canBeResend();
}
canBeResend() {
this.canResend = false;
const filter = {
where: {
year: this._date.getFullYear(),
week: this.getWeekNumber(this._date)
},
limit: 1
};
this.$http.get('WorkerTimeControlMails', {filter})
.then(res => {
if (res.data.length)
this.canResend = true;
});
}
@ -356,30 +376,25 @@ class Controller extends Section {
}
isSatisfied() {
const params = {
workerId: this.worker.id,
year: this.date.getFullYear(),
week: this.weekNumber,
state: 'CONFIRMED'
};
const query = `WorkerTimeControls/updateWorkerTimeControlMail`;
this.$http.post(query, params).then(() => {
this.getMailStates(this.date);
this.getWeekData();
this.vnApp.showSuccess(this.$t('Data saved!'));
});
this.updateWorkerTimeControlMail('CONFIRMED');
}
isUnsatisfied() {
if (!this.reason) throw new UserError(`You must indicate a reason`);
this.updateWorkerTimeControlMail('REVISE', this.reason);
}
updateWorkerTimeControlMail(state, reason) {
const params = {
workerId: this.worker.id,
year: this.date.getFullYear(),
week: this.weekNumber,
state: 'REVISE',
reason: this.reason
state
};
if (reason)
params.reason = reason;
const query = `WorkerTimeControls/updateWorkerTimeControlMail`;
this.$http.post(query, params).then(() => {
this.getMailStates(this.date);