fixes #5655 Afinar login #1516

Merged
alexandre merged 4 commits from 5655-afinar-login into dev 2023-05-22 10:36:06 +00:00
33 changed files with 483 additions and 98 deletions
Showing only changes of commit e589e70e06 - Show all commits

View File

@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2320.01] - 2023-05-25 ## [2322.01] - 2023-06-08
### Added ### Added
- -
### Changed ### Changed
- -
@ -18,6 +19,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2320.01] - 2023-05-25
### Added
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
### Changed
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
### Fixed
-
## [2318.01] - 2023-05-08 ## [2318.01] - 2023-05-08
### Added ### Added

View File

@ -55,7 +55,7 @@ async function test() {
const JunitReporter = require('jasmine-reporters'); const JunitReporter = require('jasmine-reporters');
jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000;
jasmine.exitOnCompletion = true; jasmine.exitOnCompletion = true;
} }

View File

@ -0,0 +1,12 @@
-- vn.companyL10n source
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn`.`companyL10n` AS
select
`c`.`id` AS `id`,
ifnull(`ci`.`footnotes`, `c`.`footnotes`) AS `footnotes`
from
(`vn`.`company` `c`
left join `vn`.`companyI18n` `ci` on
(`ci`.`companyFk` = `c`.`id`
and `ci`.`lang` = `util`.`LANG`()));

View File

@ -0,0 +1,73 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`clientCreate`(
vFirstname VARCHAR(50),
vSurnames VARCHAR(50),
vFi VARCHAR(9),
vAddress TEXT,
vPostcode CHAR(5),
vCity VARCHAR(25),
vProvinceFk SMALLINT(5),
vCompanyFk SMALLINT(5),
vPhone VARCHAR(11),
vEmail VARCHAR(255),
vUserFk INT)
BEGIN
/**
* Create new client
*
*/
DECLARE vPayMethodFk INT DEFAULT 4;
DECLARE vDueDay INT DEFAULT 5;
DECLARE vDefaultCredit DECIMAL(10, 2) DEFAULT 300.00;
DECLARE vIsTaxDataChecked TINYINT(1) DEFAULT 1;
DECLARE vHasCoreVnl BOOLEAN DEFAULT TRUE;
DECLARE vMandateTypeFk INT DEFAULT 2;
INSERT INTO `client` (
id,
name,
street,
fi,
phone,
email,
provinceFk,
city,
postcode,
socialName,
payMethodFk,
dueDay,
credit,
isTaxDataChecked,
hasCoreVnl,
isEqualizated)
VALUES (
vUserFk,
CONCAT(vFirstname, ' ', vSurnames),
vAddress,
TRIM(vFi),
vPhone,
vEmail,
vProvinceFk,
vCity,
vPostcode,
CONCAT(vSurnames, ' ', vFirstname),
vPayMethodFk,
vDueDay,
vDefaultCredit,
vIsTaxDataChecked,
vHasCoreVnl,
FALSE
) ON duplicate key update
payMethodFk = vPayMethodFk,
dueDay = vDueDay,
credit = vDefaultCredit,
isTaxDataChecked = vIsTaxDataChecked,
hasCoreVnl = vHasCoreVnl,
isActive = TRUE;
IF (SELECT COUNT(*) FROM mandate WHERE clientFk = vUserFk AND companyFk = vCompanyFk AND mandateTypeFk = vMandateTypeFk) = 0 THEN
INSERT INTO mandate (clientFk, companyFk, mandateTypeFk)
VALUES (vUserFk, vCompanyFk, vMandateTypeFk);
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,14 @@
INSERT INTO `vn`.`businessType` (`code`, `description`)
VALUES ('worker','Trabajador');
ALTER TABLE `vn`.`workerConfig` ADD businessTypeFk varchar(100) NULL
COMMENT 'Tipo de negocio por defecto al dar de alta un trabajador nuevo';
UPDATE `vn`.`workerConfig`
SET businessTypeFk = 'worker'
WHERE id = 1;
UPDATE `vn`.`client` c
JOIN `vn`.`worker` w ON w.id = c.id
SET c.name = REPLACE(c.name, 'TR ', ''),
c.businessTypeFk = 'worker';

View File

@ -0,0 +1,254 @@
DROP PROCEDURE IF EXISTS `vn`.`invoiceOut_new`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
vSerial VARCHAR(255),
vInvoiceDate DATE,
vTaxArea VARCHAR(25),
OUT vNewInvoiceId INT)
BEGIN
/**
* Creación de facturas emitidas.
* requiere previamente tabla tmp.ticketToInvoice(id).
*
* @param vSerial serie a la cual se hace la factura
* @param vInvoiceDate fecha de la factura
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
* @param vNewInvoiceId id de la factura que se acaba de generar
* @return vNewInvoiceId
*/
DECLARE vIsAnySaleToInvoice BOOL;
DECLARE vIsAnyServiceToInvoice BOOL;
DECLARE vNewRef VARCHAR(255);
DECLARE vWorker INT DEFAULT account.myUser_getId();
DECLARE vCompanyFk INT;
DECLARE vInterCompanyFk INT;
DECLARE vClientFk INT;
DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1;
DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6;
DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2;
DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R';
DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S';
DECLARE vNewInvoiceInFk INT;
DECLARE vIsInterCompany BOOL DEFAULT FALSE;
DECLARE vIsCEESerial BOOL DEFAULT FALSE;
DECLARE vIsCorrectInvoiceDate BOOL;
DECLARE vMaxShipped DATE;
SET vInvoiceDate = IFNULL(vInvoiceDate, util.VN_CURDATE());
SELECT t.clientFk,
t.companyFk,
MAX(DATE(t.shipped)),
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
vSerial,
t.companyFk,
YEAR(vInvoiceDate))
INTO vClientFk,
vCompanyFk,
vMaxShipped,
vIsCorrectInvoiceDate
FROM tmp.ticketToInvoice tt
JOIN ticket t ON t.id = tt.id;
IF(vMaxShipped > vInvoiceDate) THEN
CALL util.throw("Invoice date can't be less than max date");
END IF;
IF NOT vIsCorrectInvoiceDate THEN
CALL util.throw('Exists an invoice with a previous date');
END IF;
-- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
DELETE ti.*
FROM tmp.ticketToInvoice ti
JOIN ticket t ON t.id = ti.id
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN supplier su ON su.id = t.companyFk
JOIN client c ON c.id = t.clientFk
LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id AND itc.countryFk = su.countryFk
WHERE (YEAR(t.shipped) < 2001 AND t.isDeleted)
OR c.isTaxDataChecked = FALSE
OR t.isDeleted
OR c.hasToInvoice = FALSE
OR itc.id IS NULL;
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
INTO vIsAnySaleToInvoice
FROM tmp.ticketToInvoice t
JOIN sale s ON s.ticketFk = t.id;
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
FROM tmp.ticketToInvoice t
JOIN ticketService ts ON ts.ticketFk = t.id;
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
AND (vCorrectingSerial = vSerial OR NOT hasAnyNegativeBase())
THEN
-- el trigger añade el siguiente Id_Factura correspondiente a la vSerial
INSERT INTO invoiceOut(
ref,
serial,
issued,
clientFk,
dued,
companyFk,
cplusInvoiceType477Fk
)
SELECT
1,
vSerial,
vInvoiceDate,
vClientFk,
getDueDate(vInvoiceDate, dueDay),
vCompanyFk,
IF(vSerial = vCorrectingSerial,
vCplusCorrectingInvoiceTypeFk,
IF(vSerial = vSimplifiedSerial,
vCplusSimplifiedInvoiceTypeFk,
vCplusStandardInvoiceTypeFk))
FROM client
WHERE id = vClientFk;
SET vNewInvoiceId = LAST_INSERT_ID();
SELECT `ref`
INTO vNewRef
FROM invoiceOut
WHERE id = vNewInvoiceId;
UPDATE ticket t
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
SET t.refFk = vNewRef;
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
FROM tmp.ticketToInvoice ti
LEFT JOIN ticketState ts ON ti.id = ts.ticket
JOIN state s
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
INSERT INTO ticketTracking(stateFk,ticketFk,workerFk)
SELECT * FROM tmp.updateInter;
CALL invoiceExpenceMake(vNewInvoiceId);
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
UPDATE invoiceOut io
JOIN (
SELECT SUM(amount) total
FROM invoiceOutExpence
WHERE invoiceOutFk = vNewInvoiceId
) base
JOIN (
SELECT SUM(vat) total
FROM invoiceOutTax
WHERE invoiceOutFk = vNewInvoiceId
) vat
SET io.amount = base.total + vat.total
WHERE io.id = vNewInvoiceId;
DROP TEMPORARY TABLE tmp.updateInter;
SELECT COUNT(*), id
INTO vIsInterCompany, vInterCompanyFk
FROM company
WHERE clientFk = vClientFk;
IF (vIsInterCompany) THEN
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
SELECT vCompanyFk, vNewRef, vInvoiceDate, vInterCompanyFk;
SET vNewInvoiceInFk = LAST_INSERT_ID();
DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
CREATE TEMPORARY TABLE tmp.ticket
(KEY (ticketFk))
ENGINE = MEMORY
SELECT id ticketFk
FROM tmp.ticketToInvoice;
CALL `ticket_getTax`('NATIONAL');
SET @vTaxableBaseServices := 0.00;
SET @vTaxCodeGeneral := NULL;
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
SELECT vNewInvoiceInFk,
@vTaxableBaseServices,
sub.expenceFk,
sub.taxTypeSageFk,
sub.transactionTypeSageFk
FROM (
SELECT @vTaxableBaseServices := SUM(tst.taxableBase) taxableBase,
i.expenceFk,
i.taxTypeSageFk,
i.transactionTypeSageFk,
@vTaxCodeGeneral := i.taxClassCodeFk
FROM tmp.ticketServiceTax tst
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tst.code
WHERE i.isService
HAVING taxableBase
) sub;
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
SELECT vNewInvoiceInFk,
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
@vTaxableBaseServices, 0) taxableBase,
i.expenceFk,
i.taxTypeSageFk ,
i.transactionTypeSageFk
FROM tmp.ticketTax tt
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tt.code
WHERE !i.isService
GROUP BY tt.pgcFk
HAVING taxableBase
ORDER BY tt.priority;
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
SELECT COUNT(*) INTO vIsCEESerial
FROM invoiceOutSerial
WHERE code = vSerial;
IF vIsCEESerial THEN
INSERT INTO invoiceInIntrastat (
invoiceInFk,
intrastatFk,
amount,
stems,
countryFk,
net)
SELECT
vNewInvoiceInFk,
i.intrastatFk,
SUM(CAST((s.quantity * s.price * (100 - s.discount) / 100 ) AS DECIMAL(10, 2))),
SUM(CAST(IFNULL(i.stems, 1) * s.quantity AS DECIMAL(10, 2))),
su.countryFk,
CAST(SUM(IFNULL(i.stems, 1)
* s.quantity
* IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000) AS DECIMAL(10, 2))
FROM sale s
JOIN ticket t ON s.ticketFk = t.id
JOIN supplier su ON su.id = t.companyFk
JOIN item i ON i.id = s.itemFk
LEFT JOIN itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk
WHERE t.refFk = vNewRef
GROUP BY i.intrastatFk;
END IF;
DROP TEMPORARY TABLE tmp.ticket;
DROP TEMPORARY TABLE tmp.ticketAmount;
DROP TEMPORARY TABLE tmp.ticketTax;
DROP TEMPORARY TABLE tmp.ticketServiceTax;
END IF;
END IF;
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
END$$
DELIMITER ;

View File

@ -2801,9 +2801,9 @@ INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
VALUES VALUES
(1, 1); (1, 1);
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`) INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `businessTypeFk`)
VALUES VALUES
(1, NULL, 1); (1, NULL, 1, 'worker');
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`) INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
VALUES VALUES

View File

@ -50,6 +50,7 @@ describe('Item Edit basic data path', () => {
it(`should create a new intrastat and save it`, async() => { it(`should create a new intrastat and save it`, async() => {
await page.click($.newIntrastatButton); await page.click($.newIntrastatButton);
await page.waitForSelector($.intrastatForm);
await page.fillForm($.intrastatForm, { await page.fillForm($.intrastatForm, {
id: '588420239', id: '588420239',
description: 'Tropical Flowers' description: 'Tropical Flowers'

View File

@ -139,7 +139,7 @@ export default class CrudModel extends ModelProxy {
filter.limit = this.page * this.limit; filter.limit = this.page * this.limit;
} }
return this.sendRequest(filter, append, true); return this.sendRequest(filter, append);
} }
clear() { clear() {
@ -231,12 +231,12 @@ export default class CrudModel extends ModelProxy {
return params; return params;
} }
sendRequest(filter, append, loadMore) { sendRequest(filter, append) {
this.cancelRequest(); this.cancelRequest();
this.canceler = this.$q.defer(); this.canceler = this.$q.defer();
this.isPaging = append; this.isPaging = append;
if (!loadMore) if (!append && this.status != 'ready')
this.status = 'loading'; this.status = 'loading';
let params = Object.assign( let params = Object.assign(

View File

@ -150,7 +150,7 @@ describe('Component vnCrudModel', () => {
controller.loadMore(true); controller.loadMore(true);
expect(controller.sendRequest).toHaveBeenCalledWith({'skip': 2}, true, true); expect(controller.sendRequest).toHaveBeenCalledWith({'skip': 2}, true);
}); });
}); });

View File

@ -7,11 +7,10 @@ export default class DataViewer {
} }
get status() { get status() {
if (this.model)
return this.model.status;
if (this.isLoading) if (this.isLoading)
return 'loading'; return 'loading';
if (this.model)
return this.model.status;
if (!this.data) if (!this.data)
return 'clear'; return 'clear';
if (this.data.length) if (this.data.length)

View File

@ -14,9 +14,12 @@
order="changedModel" order="changedModel"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-data-viewer model="model" class="vn-w-md vn-px-sm"> <vn-data-viewer
model="model"
is-loading="model.isLoading"
class="vn-w-md vn-px-sm">
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs"> <div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
<div class="user-wrapper"> <div class="left">
<vn-avatar class="vn-mt-xs" <vn-avatar class="vn-mt-xs"
ng-class="::{system: !log.user}" ng-class="::{system: !log.user}"
val="{{::log.user ? log.user.nickname : 'System'}}" val="{{::log.user ? log.user.nickname : 'System'}}"
@ -33,7 +36,7 @@
<div class="header vn-mb-sm"> <div class="header vn-mb-sm">
<div <div
class="date text-secondary text-caption" class="date text-secondary text-caption"
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}"> title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm:ss'}}">
{{::$ctrl.relativeDate(log.creationDate)}} {{::$ctrl.relativeDate(log.creationDate)}}
</div> </div>
<span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate> <span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate>

View File

@ -4,7 +4,7 @@ vn-log {
.change { .change {
display: flex; display: flex;
& > .user-wrapper { & > .left {
position: relative; position: relative;
padding-right: 10px; padding-right: 10px;
@ -34,7 +34,7 @@ vn-log {
bottom: -8px; bottom: -8px;
} }
} }
&:last-child > .user-wrapper > .line { &:last-child > .left > .line {
display: none; display: none;
} }
.detail { .detail {

View File

@ -27,7 +27,6 @@ module.exports = Self => {
Object.assign(myOptions, options); Object.assign(myOptions, options);
const summaryObj = await getSummary(models.Client, clientFk, myOptions); const summaryObj = await getSummary(models.Client, clientFk, myOptions);
summaryObj.mana = await models.Client.getMana(clientFk, myOptions); summaryObj.mana = await models.Client.getMana(clientFk, myOptions);
summaryObj.debt = await models.Client.getDebt(clientFk, myOptions); summaryObj.debt = await models.Client.getDebt(clientFk, myOptions);
summaryObj.averageInvoiced = await models.Client.getAverageInvoiced(clientFk, myOptions); summaryObj.averageInvoiced = await models.Client.getAverageInvoiced(clientFk, myOptions);
@ -115,6 +114,12 @@ module.exports = Self => {
fields: ['claimingRate', 'priceIncreasing'], fields: ['claimingRate', 'priceIncreasing'],
limit: 1 limit: 1
} }
},
{
relation: 'businessType',
scope: {
fields: ['description']
}
} }
], ],
where: {id: clientId} where: {id: clientId}

View File

@ -64,6 +64,9 @@
<vn-label-value label="Channel" <vn-label-value label="Channel"
value="{{$ctrl.summary.contactChannel.name}}"> value="{{$ctrl.summary.contactChannel.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Business type"
value="{{$ctrl.summary.businessType.description}}">
</vn-label-value>
</vn-one> </vn-one>
<vn-one> <vn-one>
<h4 ng-show="$ctrl.isEmployee"> <h4 ng-show="$ctrl.isEmployee">

View File

@ -23,3 +23,4 @@ Latest tickets: Últimos tickets
Rating: Clasificación Rating: Clasificación
Value from 1 to 20. The higher the better value: Valor del 1 al 20. Cuanto más alto mejor valoración Value from 1 to 20. The higher the better value: Valor del 1 al 20. Cuanto más alto mejor valoración
Go to grafana: Ir a grafana Go to grafana: Ir a grafana
Business type: Tipo de negocio

View File

@ -2,8 +2,8 @@
vn-fixed-price{ vn-fixed-price{
smart-table table{ smart-table table{
[shrink-field]{ [shrink-field]{
width: 80px; width: 90px;
max-width: 80px; max-width: 90px;
} }
[shrink-field-expand]{ [shrink-field-expand]{
width: 150px; width: 150px;
@ -15,8 +15,8 @@ vn-fixed-price{
align-items: center; align-items: center;
text-align: center; text-align: center;
vn-input-number { vn-input-number {
width: 90px; width: 75px;
max-width: 90px; max-width: 75px;
} }
} }

View File

@ -1,3 +1,4 @@
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('editableStates', { Self.remoteMethodCtx('editableStates', {
description: 'Gets the editable states according the user role ', description: 'Gets the editable states according the user role ',
@ -19,25 +20,16 @@ module.exports = Self => {
Self.editableStates = async(ctx, filter, options) => { Self.editableStates = async(ctx, filter, options) => {
const models = Self.app.models; const models = Self.app.models;
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const myOptions = {}; const myOptions = {...(options || {})};
if (typeof options == 'object')
Object.assign(myOptions, options);
let statesList = await models.State.find(filter, myOptions);
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions); const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions); const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
if (isProduction || isAdministrative) if (!isProduction && !isAdministrative)
return statesList; filter = mergeFilters(filter, {where: {alertLevel: 0}});
if (isSalesPerson) { const states = await models.State.find(filter, myOptions);
return statesList = statesList.filter(stateList =>
stateList.alertLevel === 0 || stateList.code === 'PICKER_DESIGNED'
);
}
return statesList.filter(stateList => stateList.alertLevel === 0); return states;
}; };
}; };

View File

@ -24,31 +24,6 @@ describe('ticket editableStates()', () => {
} }
}); });
it(`should return the expected states by a specific role`, async() => {
const tx = await models.State.beginTransaction({});
try {
const options = {transaction: tx};
const productionRole = 18;
const ctx = {req: {accessToken: {userId: productionRole}}};
const editableStates = await models.State.editableStates(ctx, filter, options);
const deliveredState = editableStates.some(state => state.code == 'DELIVERED');
const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED');
expect(deliveredState).toBeFalsy();
expect(pickerDesignedState).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`should return again the expected state by a specific role`, async() => { it(`should return again the expected state by a specific role`, async() => {
const tx = await models.State.beginTransaction({}); const tx = await models.State.beginTransaction({});
@ -70,4 +45,25 @@ describe('ticket editableStates()', () => {
throw e; throw e;
} }
}); });
it(`should return the expected state matching with the name`, async() => {
const tx = await models.State.beginTransaction({});
try {
const options = {transaction: tx};
const employeeRole = 1;
const ctx = {req: {accessToken: {userId: employeeRole}}};
const filter = {where: {name: {like: '%Previa OK%'}}};
const [editableStates] = await models.State.editableStates(ctx, filter, options);
expect(editableStates.name).toBe('Previa OK');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
}); });

View File

@ -124,6 +124,7 @@ module.exports = Self => {
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions); const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
if (!isDeliveryBoss) { if (!isDeliveryBoss) {
const zoneShipped = await models.Agency.getShipped( const zoneShipped = await models.Agency.getShipped(
ctx,
args.landed, args.landed,
args.addressFk, args.addressFk,
args.agencyModeFk, args.agencyModeFk,

View File

@ -24,7 +24,6 @@ module.exports = function(Self) {
}); });
Self.makeInvoice = async(ctx, ticketsIds, options) => { Self.makeInvoice = async(ctx, ticketsIds, options) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models; const models = Self.app.models;
const date = Date.vnNew(); const date = Date.vnNew();
date.setHours(0, 0, 0, 0); date.setHours(0, 0, 0, 0);
@ -42,6 +41,7 @@ module.exports = function(Self) {
let serial; let serial;
let invoiceId; let invoiceId;
let invoiceOut;
try { try {
const tickets = await models.Ticket.find({ const tickets = await models.Ticket.find({
where: { where: {
@ -89,24 +89,14 @@ module.exports = function(Self) {
invoiceId = resultInvoice.id; invoiceId = resultInvoice.id;
for (let ticket of tickets) {
const ticketInvoice = await models.Ticket.findById(ticket.id, {
fields: ['refFk']
}, myOptions);
await models.TicketLog.create({
originFk: ticket.id,
userFk: userId,
action: 'insert',
changedModel: 'Ticket',
changedModelId: ticket.id,
newInstance: ticketInvoice
}, myOptions);
}
if (serial != 'R' && invoiceId) if (serial != 'R' && invoiceId)
await Self.rawSql('CALL invoiceOutBooking(?)', [invoiceId], myOptions); await Self.rawSql('CALL invoiceOutBooking(?)', [invoiceId], myOptions);
invoiceOut = await models.InvoiceOut.findById(invoiceId, {
include: {
relation: 'client'
}
}, myOptions);
if (tx) await tx.commit(); if (tx) await tx.commit();
} catch (e) { } catch (e) {
if (tx) await tx.rollback(); if (tx) await tx.rollback();
@ -116,6 +106,15 @@ module.exports = function(Self) {
if (serial != 'R' && invoiceId) if (serial != 'R' && invoiceId)
await models.InvoiceOut.createPdf(ctx, invoiceId); await models.InvoiceOut.createPdf(ctx, invoiceId);
if (invoiceId) {
ctx.args = {
reference: invoiceOut.ref,
recipientId: invoiceOut.clientFk,
recipient: invoiceOut.client().email
};
await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref);
}
return {invoiceFk: invoiceId, serial: serial}; return {invoiceFk: invoiceId, serial: serial};
}; };
}; };

View File

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

View File

@ -81,6 +81,7 @@ module.exports = Self => {
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions); const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
if (!isDeliveryBoss) { if (!isDeliveryBoss) {
const zoneShipped = await models.Agency.getShipped( const zoneShipped = await models.Agency.getShipped(
ctx,
args.landed, args.landed,
args.addressId, args.addressId,
args.agencyModeId, args.agencyModeId,

View File

@ -6,6 +6,9 @@ describe('ticket makeInvoice()', () => {
const ticketId = 11; const ticketId = 11;
const clientId = 1102; const clientId = 1102;
const activeCtx = { const activeCtx = {
getLocale: () => {
return 'en';
},
accessToken: {userId: userId}, accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'}, headers: {origin: 'http://localhost:5000'},
}; };
@ -67,6 +70,7 @@ describe('ticket makeInvoice()', () => {
it('should invoice a ticket, then try again to fail', async() => { it('should invoice a ticket, then try again to fail', async() => {
const invoiceOutModel = models.InvoiceOut; const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'createPdf'); spyOn(invoiceOutModel, 'createPdf');
spyOn(invoiceOutModel, 'invoiceEmail');
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
@ -90,6 +94,7 @@ describe('ticket makeInvoice()', () => {
it('should success to invoice a ticket', async() => { it('should success to invoice a ticket', async() => {
const invoiceOutModel = models.InvoiceOut; const invoiceOutModel = models.InvoiceOut;
spyOn(invoiceOutModel, 'createPdf'); spyOn(invoiceOutModel, 'createPdf');
spyOn(invoiceOutModel, 'invoiceEmail');
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});

View File

@ -1,4 +1,4 @@
/* eslint max-len: ["error", { "code": 130 }]*/ /* eslint max-len: ["error", { "code": 150 }]*/
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
@ -139,7 +139,7 @@ module.exports = Self => {
if (!client) { if (!client) {
const nickname = args.firstName.concat(' ', args.lastNames); const nickname = args.firstName.concat(' ', args.lastNames);
const workerConfig = await models.WorkerConfig.findOne({fields: ['roleFk']}); const workerConfig = await models.WorkerConfig.findOne({fields: ['roleFk', 'businessTypeFk']});
const [randomPassword] = await models.Worker.rawSql( const [randomPassword] = await models.Worker.rawSql(
'SELECT account.passwordGenerate() as password;' 'SELECT account.passwordGenerate() as password;'
); );
@ -196,7 +196,7 @@ module.exports = Self => {
client = await models.Client.findById( client = await models.Client.findById(
user.id, user.id,
{fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'fi']}, {fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'businessTypeFk', 'fi']},
myOptions myOptions
); );
@ -205,6 +205,7 @@ module.exports = Self => {
iban: args.iban, iban: args.iban,
bankEntityFk: args.bankEntityFk, bankEntityFk: args.bankEntityFk,
defaultAddressFk: address.id, defaultAddressFk: address.id,
businessTypeFk: workerConfig.businessTypeFk,
}, },
myOptions myOptions
); );

View File

@ -14,6 +14,9 @@
}, },
"roleFk": { "roleFk": {
"type": "number" "type": "number"
},
"businessTypeFk": {
"type": "string"
} }
}, },
"acls": [ "acls": [

View File

@ -1,7 +1,7 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('getShipped', { Self.remoteMethodCtx('getShipped', {
description: 'Returns the first shipped possible for params', description: 'Returns the first shipped possible for params',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
@ -34,18 +34,22 @@ module.exports = Self => {
} }
}); });
Self.getShipped = async(landed, addressFk, agencyModeFk, warehouseFk, options) => { Self.getShipped = async(ctx, landed, addressFk, agencyModeFk, warehouseFk, options) => {
const myOptions = {}; const myOptions = {};
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
const stmts = []; const stmts = [];
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const isProductionAssistant = await models.VnUser.hasRole(userId, 'productionAssi', myOptions);
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CALL vn.zone_getShipped(?, ?, ?, TRUE)`, [ `CALL vn.zone_getShipped(?, ?, ?, ?)`, [
landed, landed,
addressFk, addressFk,
agencyModeFk agencyModeFk,
isProductionAssistant
] ]
)); ));

View File

@ -1,6 +1,9 @@
const {models} = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('agency getShipped()', () => { describe('agency getShipped()', () => {
const employeeId = 1;
const ctx = {req: {accessToken: {userId: employeeId}}};
it('should return a shipment date', async() => { it('should return a shipment date', async() => {
const landed = Date.vnNew(); const landed = Date.vnNew();
landed.setDate(landed.getDate() + 1); landed.setDate(landed.getDate() + 1);
@ -12,8 +15,7 @@ describe('agency getShipped()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await models.Agency.getShipped(ctx, landed, addressFk, agencyModeFk, warehouseFk, options);
const result = await models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk, options);
expect(result).toBeDefined(); expect(result).toBeDefined();
@ -37,7 +39,7 @@ describe('agency getShipped()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk, options); const result = await models.Agency.getShipped(ctx, landed, addressFk, agencyModeFk, warehouseFk, options);
expect(result).toBeUndefined(); expect(result).toBeUndefined();

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "salix-back", "name": "salix-back",
"version": "23.18.01", "version": "23.22.01",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"packages": { "packages": {

View File

@ -1,6 +1,6 @@
{ {
"name": "salix-back", "name": "salix-back",
"version": "23.20.01", "version": "23.22.01",
"author": "Verdnatura Levante SL", "author": "Verdnatura Levante SL",
"description": "Salix backend", "description": "Salix backend",
"license": "GPL-3.0", "license": "GPL-3.0",

View File

@ -4,13 +4,14 @@ const db = require('../../database');
module.exports = { module.exports = {
name: 'report-footer', name: 'report-footer',
async serverPrefetch() { async serverPrefetch() {
this.company = await db.findOne( this.company = await db.findOne(`
`SELECT SELECT IFNULL(ci.footnotes, cl.footnotes) as footnotes
ci.footnotes FROM company c
FROM companyI18n ci LEFT JOIN companyL10n cl ON c.id = cl.id
JOIN company c ON c.id = ci.companyFk LEFT JOIN companyI18n ci ON ci.companyFk = cl.id
WHERE c.code = ? AND ci.lang = (SELECT lang FROM account.user WHERE id = ?)`, AND ci.lang = (SELECT lang FROM account.user where id = ?)
[this.companyCode, this.recipientId]); WHERE c.code = ?`,
[this.recipientId, this.companyCode]);
}, },
props: ['leftText', 'companyCode', 'recipientId', 'centerText'] props: ['leftText', 'companyCode', 'recipientId', 'centerText']