Merge pull request '2661 - Added clone options' (#494) from 2661-travel_cloneWithEntries into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #494 Reviewed-by: Carlos Jimenez Ruiz <carlosjr@verdnatura.es>
This commit is contained in:
commit
1a3cc54dd2
|
@ -0,0 +1,135 @@
|
||||||
|
-- DROP PROCEDURE `vn`.`clonTravelComplete`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
USE `vn`$$
|
||||||
|
CREATE
|
||||||
|
DEFINER = root@`%` PROCEDURE `vn`.`travel_cloneWithEntries`(IN vTravelFk INT, IN vDateStart DATE, IN vDateEnd DATE,
|
||||||
|
IN vRef VARCHAR(255), OUT vNewTravelFk INT)
|
||||||
|
BEGIN
|
||||||
|
DECLARE vEntryNew INT;
|
||||||
|
DECLARE vDone BOOLEAN DEFAULT FALSE;
|
||||||
|
DECLARE vAuxEntryFk INT;
|
||||||
|
DECLARE vRsEntry CURSOR FOR
|
||||||
|
SELECT e.id
|
||||||
|
FROM entry e
|
||||||
|
JOIN travel t
|
||||||
|
ON t.id = e.travelFk
|
||||||
|
WHERE e.travelFk = vTravelFk;
|
||||||
|
|
||||||
|
DECLARE vRsBuy CURSOR FOR
|
||||||
|
SELECT b.*
|
||||||
|
FROM buy b
|
||||||
|
JOIN entry e
|
||||||
|
ON b.entryFk = e.id
|
||||||
|
WHERE e.travelFk = vNewTravelFk and b.entryFk=vNewTravelFk
|
||||||
|
ORDER BY e.id;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
ROLLBACK;
|
||||||
|
RESIGNAL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
INSERT INTO travel (shipped,landed, warehouseInFk, warehouseOutFk, agencyFk, ref, isDelivered, isReceived, m3, kg)
|
||||||
|
SELECT vDateStart, vDateEnd,warehouseInFk, warehouseOutFk, agencyFk, vRef, isDelivered, isReceived, m3, kg
|
||||||
|
FROM travel
|
||||||
|
WHERE id = vTravelFk;
|
||||||
|
|
||||||
|
SET vNewTravelFk = LAST_INSERT_ID();
|
||||||
|
SET vDone = FALSE;
|
||||||
|
OPEN vRsEntry ;
|
||||||
|
FETCH vRsEntry INTO vAuxEntryFk;
|
||||||
|
|
||||||
|
WHILE NOT vDone DO
|
||||||
|
INSERT INTO entry (supplierFk,
|
||||||
|
ref,
|
||||||
|
isInventory,
|
||||||
|
isConfirmed,
|
||||||
|
isOrdered,
|
||||||
|
isRaid,
|
||||||
|
commission,
|
||||||
|
created,
|
||||||
|
evaNotes,
|
||||||
|
travelFk,
|
||||||
|
currencyFk,
|
||||||
|
companyFk,
|
||||||
|
gestDocFk,
|
||||||
|
invoiceInFk)
|
||||||
|
SELECT supplierFk,
|
||||||
|
ref,
|
||||||
|
isInventory,
|
||||||
|
isConfirmed,
|
||||||
|
isOrdered,
|
||||||
|
isRaid,
|
||||||
|
commission,
|
||||||
|
created,
|
||||||
|
evaNotes,
|
||||||
|
vNewTravelFk,
|
||||||
|
currencyFk,
|
||||||
|
companyFk,
|
||||||
|
gestDocFk,
|
||||||
|
invoiceInFk
|
||||||
|
FROM entry
|
||||||
|
WHERE id = vAuxEntryFk;
|
||||||
|
|
||||||
|
SET vEntryNew = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO buy (entryFk,
|
||||||
|
itemFk,
|
||||||
|
quantity,
|
||||||
|
buyingValue,
|
||||||
|
packageFk,
|
||||||
|
stickers,
|
||||||
|
freightValue,
|
||||||
|
packageValue,
|
||||||
|
comissionValue,
|
||||||
|
packing,
|
||||||
|
`grouping`,
|
||||||
|
groupingMode,
|
||||||
|
location,
|
||||||
|
price1,
|
||||||
|
price2,
|
||||||
|
price3,
|
||||||
|
minPrice,
|
||||||
|
producer,
|
||||||
|
printedStickers,
|
||||||
|
isChecked,
|
||||||
|
weight)
|
||||||
|
SELECT vEntryNew,
|
||||||
|
itemFk,
|
||||||
|
quantity,
|
||||||
|
buyingValue,
|
||||||
|
packageFk,
|
||||||
|
stickers,
|
||||||
|
freightValue,
|
||||||
|
packageValue,
|
||||||
|
comissionValue,
|
||||||
|
packing,
|
||||||
|
`grouping`,
|
||||||
|
groupingMode,
|
||||||
|
location,
|
||||||
|
price1,
|
||||||
|
price2,
|
||||||
|
price3,
|
||||||
|
minPrice,
|
||||||
|
producer,
|
||||||
|
printedStickers,
|
||||||
|
isChecked,
|
||||||
|
weight
|
||||||
|
FROM buy
|
||||||
|
WHERE entryFk = vAuxEntryFk;
|
||||||
|
|
||||||
|
|
||||||
|
FETCH vRsEntry INTO vAuxEntryFk;
|
||||||
|
END WHILE;
|
||||||
|
CLOSE vRsEntry;
|
||||||
|
COMMIT;
|
||||||
|
END;$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
|
|
@ -831,7 +831,8 @@ export default {
|
||||||
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)'
|
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)'
|
||||||
},
|
},
|
||||||
travelExtraCommunity: {
|
travelExtraCommunity: {
|
||||||
firstTravelReference: 'vn-travel-extra-community > vn-data-viewer div > vn-tbody > vn-tr > vn-td-editable',
|
anySearchResult: 'vn-travel-extra-community > vn-data-viewer div > vn-tbody > vn-tr',
|
||||||
|
firstTravelReference: 'vn-travel-extra-community vn-card:nth-child(1) vn-td-editable',
|
||||||
removeContinentFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(3) > vn-icon > i'
|
removeContinentFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(3) > vn-icon > i'
|
||||||
},
|
},
|
||||||
travelBasicData: {
|
travelBasicData: {
|
||||||
|
@ -863,7 +864,18 @@ export default {
|
||||||
travelDescriptor: {
|
travelDescriptor: {
|
||||||
filterByAgencyButton: 'vn-descriptor-content .quicklinks > div:nth-child(1) > vn-quick-link > a[vn-tooltip="All travels with current agency"]',
|
filterByAgencyButton: 'vn-descriptor-content .quicklinks > div:nth-child(1) > vn-quick-link > a[vn-tooltip="All travels with current agency"]',
|
||||||
dotMenu: 'vn-travel-descriptor vn-icon-button[icon="more_vert"]',
|
dotMenu: 'vn-travel-descriptor vn-icon-button[icon="more_vert"]',
|
||||||
dotMenuClone: '#clone'
|
dotMenuClone: '#clone',
|
||||||
|
dotMenuCloneWithEntries: '#cloneWithEntries',
|
||||||
|
acceptClonation: 'tpl-buttons > button[response="accept"]'
|
||||||
|
},
|
||||||
|
travelCreate: {
|
||||||
|
reference: 'vn-travel-create vn-textfield[ng-model="$ctrl.travel.ref"]',
|
||||||
|
agency: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.agencyModeFk"]',
|
||||||
|
shipped: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.shipped"]',
|
||||||
|
landed: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.landed"]',
|
||||||
|
warehouseOut: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]',
|
||||||
|
warehouseIn: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]',
|
||||||
|
saveButton: 'vn-travel-create vn-submit[label="Save"]'
|
||||||
},
|
},
|
||||||
zoneIndex: {
|
zoneIndex: {
|
||||||
searchResult: 'vn-zone-index a.vn-tr',
|
searchResult: 'vn-zone-index a.vn-tr',
|
||||||
|
|
|
@ -74,6 +74,7 @@ describe('Route create path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should clone the first route`, async() => {
|
it(`should clone the first route`, async() => {
|
||||||
|
await page.waitForTimeout(1000); // needs time for the index to show all items
|
||||||
await page.waitToClick(selectors.routeIndex.firstRouteCheckbox);
|
await page.waitToClick(selectors.routeIndex.firstRouteCheckbox);
|
||||||
await page.waitToClick(selectors.routeIndex.cloneButton);
|
await page.waitToClick(selectors.routeIndex.cloneButton);
|
||||||
await page.waitToClick(selectors.routeIndex.submitClonationButton);
|
await page.waitToClick(selectors.routeIndex.submitClonationButton);
|
||||||
|
|
|
@ -42,4 +42,48 @@ describe('Travel descriptor path', () => {
|
||||||
|
|
||||||
expect(state).toBe('travel.create');
|
expect(state).toBe('travel.create');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should edit the data to clone and then get redirected to the cloned travel basic data', async() => {
|
||||||
|
await page.clearInput(selectors.travelCreate.reference);
|
||||||
|
await page.write(selectors.travelCreate.reference, 'reference');
|
||||||
|
await page.autocompleteSearch(selectors.travelCreate.agency, 'entanglement');
|
||||||
|
await page.pickDate(selectors.travelCreate.shipped);
|
||||||
|
await page.pickDate(selectors.travelCreate.landed);
|
||||||
|
await page.autocompleteSearch(selectors.travelCreate.warehouseOut, 'warehouse one');
|
||||||
|
await page.autocompleteSearch(selectors.travelCreate.warehouseIn, 'warehouse two');
|
||||||
|
await page.waitToClick(selectors.travelCreate.saveButton);
|
||||||
|
await page.waitForState('travel.card.basicData');
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should atempt to clone the travel and its entries using the descriptor menu but receive an error', async() => {
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.dotMenu);
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.dotMenuCloneWithEntries);
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.acceptClonation);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('A travel with this data already exists');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the landed date to a future date to enable cloneWithEntries', async() => {
|
||||||
|
const nextMonth = new Date();
|
||||||
|
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
||||||
|
await page.pickDate(selectors.travelBasicData.deliveryDate, nextMonth);
|
||||||
|
await page.waitToClick(selectors.travelBasicData.save);
|
||||||
|
await page.waitForState('travel.card.basicData');
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to the summary and then clone the travel and its entries using the descriptor menu to get redirected to the cloned travel basic data', async() => {
|
||||||
|
await page.waitToClick('vn-icon[icon="preview"]'); // summary icon
|
||||||
|
await page.waitForState('travel.card.summary');
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.dotMenu);
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.dotMenuCloneWithEntries);
|
||||||
|
await page.waitToClick(selectors.travelDescriptor.acceptClonation);
|
||||||
|
await page.waitForState('travel.card.basicData');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,7 @@ describe('Travel extra community path', () => {
|
||||||
|
|
||||||
it('should edit the travel reference', async() => {
|
it('should edit the travel reference', async() => {
|
||||||
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
|
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
|
||||||
|
await page.waitForSpinnerLoad();
|
||||||
await page.writeOnEditableTD(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
|
await page.writeOnEditableTD(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,9 @@ exports.translateValues = async(instance, changes) => {
|
||||||
}).format(date);
|
}).format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changes instanceof instance)
|
||||||
|
changes = changes.__data;
|
||||||
|
|
||||||
const properties = Object.assign({}, changes);
|
const properties = Object.assign({}, changes);
|
||||||
for (let property in properties) {
|
for (let property in properties) {
|
||||||
const relation = getRelation(instance, property);
|
const relation = getRelation(instance, property);
|
||||||
|
@ -41,13 +44,14 @@ exports.translateValues = async(instance, changes) => {
|
||||||
|
|
||||||
if (relation) {
|
if (relation) {
|
||||||
let fieldsToShow = ['alias', 'name', 'code', 'description'];
|
let fieldsToShow = ['alias', 'name', 'code', 'description'];
|
||||||
const log = instance.definition.settings.log;
|
const modelName = relation.model;
|
||||||
|
const model = models[modelName];
|
||||||
|
const log = model.definition.settings.log;
|
||||||
|
|
||||||
if (log && log.showField)
|
if (log && log.showField)
|
||||||
fieldsToShow = log.showField;
|
fieldsToShow = [log.showField];
|
||||||
|
|
||||||
const model = relation.model;
|
const row = await model.findById(value, {
|
||||||
const row = await models[model].findById(value, {
|
|
||||||
fields: fieldsToShow
|
fields: fieldsToShow
|
||||||
});
|
});
|
||||||
const newValue = getValue(row);
|
const newValue = getValue(row);
|
||||||
|
|
|
@ -23,23 +23,27 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'account',
|
arg: 'account',
|
||||||
type: 'string'
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'sageTaxTypeFk',
|
arg: 'sageTaxTypeFk',
|
||||||
type: 'number'
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'sageWithholdingFk',
|
arg: 'sageWithholdingFk',
|
||||||
type: 'number'
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'sageTransactionTypeFk',
|
arg: 'sageTransactionTypeFk',
|
||||||
type: 'number'
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'postCode',
|
arg: 'postCode',
|
||||||
type: 'string'
|
type: 'any'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'street',
|
||||||
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'city',
|
arg: 'city',
|
||||||
|
@ -47,11 +51,11 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'provinceFk',
|
arg: 'provinceFk',
|
||||||
type: 'number'
|
type: 'any'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'countryFk',
|
arg: 'countryFk',
|
||||||
type: 'number'
|
type: 'any'
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
arg: 'res',
|
arg: 'res',
|
||||||
|
|
|
@ -130,7 +130,7 @@ module.exports = Self => {
|
||||||
let logRecord = {
|
let logRecord = {
|
||||||
originFk: cleanInstance.id,
|
originFk: cleanInstance.id,
|
||||||
userFk: myUserId,
|
userFk: myUserId,
|
||||||
action: 'create',
|
action: 'insert',
|
||||||
changedModel: 'Ticket',
|
changedModel: 'Ticket',
|
||||||
changedModelId: cleanInstance.id,
|
changedModelId: cleanInstance.id,
|
||||||
oldInstance: {},
|
oldInstance: {},
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
const loggable = require('vn-loopback/util/log');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('cloneWithEntries', {
|
||||||
|
description: 'Clone travel',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The original travel id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
description: 'The new cloned travel id',
|
||||||
|
root: true,
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/cloneWithEntries`,
|
||||||
|
verb: 'post'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.cloneWithEntries = async(ctx, id) => {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const conn = Self.dataSource.connector;
|
||||||
|
const models = Self.app.models;
|
||||||
|
const travel = await Self.findById(id, {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'shipped',
|
||||||
|
'landed',
|
||||||
|
'warehouseInFk',
|
||||||
|
'warehouseOutFk',
|
||||||
|
'agencyFk',
|
||||||
|
'ref'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const started = new Date();
|
||||||
|
const ended = new Date();
|
||||||
|
|
||||||
|
if (!travel)
|
||||||
|
throw new UserError('Travel not found');
|
||||||
|
|
||||||
|
let stmts = [];
|
||||||
|
let stmt;
|
||||||
|
|
||||||
|
try {
|
||||||
|
stmt = new ParameterizedSQL(
|
||||||
|
`CALL travel_cloneWithEntries(?, ?, ?, ?, @vTravelFk)`, [
|
||||||
|
id, started, ended, travel.ref]);
|
||||||
|
|
||||||
|
stmts.push(stmt);
|
||||||
|
const index = stmts.push('SELECT @vTravelFk AS id') - 1;
|
||||||
|
|
||||||
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
|
const result = await conn.executeStmt(sql);
|
||||||
|
const [lastInsert] = result[index];
|
||||||
|
const newTravel = await Self.findById(lastInsert.id, {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'shipped',
|
||||||
|
'landed',
|
||||||
|
'warehouseInFk',
|
||||||
|
'warehouseOutFk',
|
||||||
|
'agencyFk',
|
||||||
|
'ref'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldProperties = await loggable.translateValues(Self, travel);
|
||||||
|
const newProperties = await loggable.translateValues(Self, newTravel);
|
||||||
|
await models.TravelLog.create({
|
||||||
|
originFk: newTravel.id,
|
||||||
|
userFk: userId,
|
||||||
|
action: 'insert',
|
||||||
|
changedModel: 'Travel',
|
||||||
|
changedModelId: newTravel.id,
|
||||||
|
oldInstance: oldProperties,
|
||||||
|
newInstance: newProperties
|
||||||
|
});
|
||||||
|
|
||||||
|
return newTravel.id;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ER_DUP_ENTRY')
|
||||||
|
throw new UserError('A travel with this data already exists');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,79 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
// #2687 - Cannot make a data rollback because of the triggers
|
||||||
|
xdescribe('Travel cloneWithEntries()', () => {
|
||||||
|
const models = app.models;
|
||||||
|
const travelId = 5;
|
||||||
|
const currentUserId = 102;
|
||||||
|
const ctx = {req: {accessToken: {userId: currentUserId}}};
|
||||||
|
let travelBefore;
|
||||||
|
let newTravelId;
|
||||||
|
|
||||||
|
afterAll(async done => {
|
||||||
|
try {
|
||||||
|
const entries = await models.Entry.find({
|
||||||
|
where: {
|
||||||
|
travelFk: newTravelId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const entriesId = entries.map(entry => entry.id);
|
||||||
|
|
||||||
|
// Destroy all entries buys
|
||||||
|
await models.Buy.destroyAll({
|
||||||
|
where: {
|
||||||
|
entryFk: {inq: entriesId}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Destroy travel entries
|
||||||
|
await models.Entry.destroyAll({
|
||||||
|
where: {
|
||||||
|
travelFk: newTravelId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Destroy new travel
|
||||||
|
await models.Travel.destroyById(newTravelId);
|
||||||
|
|
||||||
|
// Restore original travel shipped & landed
|
||||||
|
const travel = await models.Travel.findById(travelId);
|
||||||
|
await travel.updateAttributes({
|
||||||
|
shipped: travelBefore.shipped,
|
||||||
|
landed: travelBefore.landed
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should clone the travel and the containing entries`, async() => {
|
||||||
|
const warehouseThree = 3;
|
||||||
|
const agencyModeOne = 1;
|
||||||
|
const yesterday = new Date();
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
|
||||||
|
travelBefore = await models.Travel.findById(travelId);
|
||||||
|
await travelBefore.updateAttributes({
|
||||||
|
shipped: yesterday,
|
||||||
|
landed: yesterday
|
||||||
|
});
|
||||||
|
|
||||||
|
newTravelId = await models.Travel.cloneWithEntries(ctx, travelId);
|
||||||
|
const travelEntries = await models.Entry.find({
|
||||||
|
where: {
|
||||||
|
travelFk: newTravelId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const newTravel = await models.Travel.findById(travelId);
|
||||||
|
|
||||||
|
expect(newTravelId).not.toEqual(travelId);
|
||||||
|
expect(newTravel.ref).toEqual('fifth travel');
|
||||||
|
expect(newTravel.warehouseInFk).toEqual(warehouseThree);
|
||||||
|
expect(newTravel.warehouseOutFk).toEqual(warehouseThree);
|
||||||
|
expect(newTravel.agencyFk).toEqual(agencyModeOne);
|
||||||
|
expect(travelEntries.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,6 +8,7 @@ module.exports = Self => {
|
||||||
require('../methods/travel/deleteThermograph')(Self);
|
require('../methods/travel/deleteThermograph')(Self);
|
||||||
require('../methods/travel/updateThermograph')(Self);
|
require('../methods/travel/updateThermograph')(Self);
|
||||||
require('../methods/travel/extraCommunityFilter')(Self);
|
require('../methods/travel/extraCommunityFilter')(Self);
|
||||||
|
require('../methods/travel/cloneWithEntries')(Self);
|
||||||
|
|
||||||
Self.rewriteDbError(function(err) {
|
Self.rewriteDbError(function(err) {
|
||||||
if (err.code === 'ER_DUP_ENTRY')
|
if (err.code === 'ER_DUP_ENTRY')
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-button-bar>
|
<vn-button-bar>
|
||||||
<vn-submit
|
<vn-submit
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Save">
|
label="Save">
|
||||||
</vn-submit>
|
</vn-submit>
|
||||||
<vn-button
|
<vn-button
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Controller extends Section {
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
return this.$.watcher.submit().then(
|
return this.$.watcher.submit().then(
|
||||||
res => this.$state.go('travel.card.summary', {id: res.data.id})
|
res => this.$state.go('travel.card.basicData', {id: res.data.id})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ describe('Travel Component vnTravelCreate', () => {
|
||||||
|
|
||||||
controller.onSubmit();
|
controller.onSubmit();
|
||||||
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('travel.card.summary', {id: 1234});
|
expect(controller.$state.go).toHaveBeenCalledWith('travel.card.basicData', {id: 1234});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,4 +39,3 @@ describe('Travel Component vnTravelCreate', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,17 @@
|
||||||
<vn-item
|
<vn-item
|
||||||
id="clone"
|
id="clone"
|
||||||
ng-click="clone.show()"
|
ng-click="clone.show()"
|
||||||
|
ng-show="::$ctrl.isBuyer"
|
||||||
translate>
|
translate>
|
||||||
Clone travel
|
Clone travel
|
||||||
</vn-item>
|
</vn-item>
|
||||||
|
<vn-item
|
||||||
|
id="cloneWithEntries"
|
||||||
|
ng-click="cloneWithEntries.show()"
|
||||||
|
ng-show="::$ctrl.isBuyer"
|
||||||
|
translate>
|
||||||
|
Clone travel and his entries
|
||||||
|
</vn-item>
|
||||||
</vn-list>
|
</vn-list>
|
||||||
</vn-menu>
|
</vn-menu>
|
||||||
|
|
||||||
|
@ -20,3 +28,11 @@
|
||||||
question="Do you want to clone this travel?"
|
question="Do you want to clone this travel?"
|
||||||
message="All it's properties will be copied">
|
message="All it's properties will be copied">
|
||||||
</vn-confirm>
|
</vn-confirm>
|
||||||
|
|
||||||
|
<!-- Clone travel popup -->
|
||||||
|
<vn-confirm
|
||||||
|
vn-id="cloneWithEntries"
|
||||||
|
on-accept="$ctrl.onCloneWithEntriesAccept()"
|
||||||
|
question="Do you want to clone this travel and all containing entries?"
|
||||||
|
message="All it's properties will be copied">
|
||||||
|
</vn-confirm>
|
||||||
|
|
|
@ -48,6 +48,10 @@ class Controller extends Section {
|
||||||
.then(res => this.travel = res.data);
|
.then(res => this.travel = res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isBuyer() {
|
||||||
|
return this.aclService.hasAny(['buyer']);
|
||||||
|
}
|
||||||
|
|
||||||
onCloneAccept() {
|
onCloneAccept() {
|
||||||
const params = JSON.stringify({
|
const params = JSON.stringify({
|
||||||
ref: this.travel.ref,
|
ref: this.travel.ref,
|
||||||
|
@ -59,6 +63,11 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
this.$state.go('travel.create', {q: params});
|
this.$state.go('travel.create', {q: params});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCloneWithEntriesAccept() {
|
||||||
|
this.$http.post(`Travels/${this.travelId}/cloneWithEntries`)
|
||||||
|
.then(res => this.$state.go('travel.card.basicData', {id: res.data}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
Controller.$inject = ['$element', '$scope'];
|
||||||
|
|
|
@ -2,11 +2,14 @@ import './index.js';
|
||||||
|
|
||||||
describe('Travel Component vnTravelDescriptorMenu', () => {
|
describe('Travel Component vnTravelDescriptorMenu', () => {
|
||||||
let controller;
|
let controller;
|
||||||
|
let $httpBackend;
|
||||||
beforeEach(ngModule('travel'));
|
beforeEach(ngModule('travel'));
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $state,) => {
|
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
const $element = angular.element('<vn-travel-descriptor-menu></vn-travel-descriptor-menu>');
|
const $element = angular.element('<vn-travel-descriptor-menu></vn-travel-descriptor-menu>');
|
||||||
controller = $componentController('vnTravelDescriptorMenu', {$element});
|
controller = $componentController('vnTravelDescriptorMenu', {$element});
|
||||||
|
controller._travelId = 5;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('onCloneAccept()', () => {
|
describe('onCloneAccept()', () => {
|
||||||
|
@ -36,4 +39,18 @@ describe('Travel Component vnTravelDescriptorMenu', () => {
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('travel.create', {'q': params});
|
expect(controller.$state.go).toHaveBeenCalledWith('travel.create', {'q': params});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('onCloneWithEntriesAccept()', () => {
|
||||||
|
it('should make an HTTP query and then call to the $state.go method with the returned id', () => {
|
||||||
|
jest.spyOn(controller.$state, 'go').mockReturnValue('ok');
|
||||||
|
|
||||||
|
$httpBackend.expect('POST', `Travels/${controller.travelId}/cloneWithEntries`).respond(200, 9);
|
||||||
|
controller.onCloneWithEntriesAccept();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.$state.go).toHaveBeenCalledWith('travel.card.basicData', {
|
||||||
|
id: jasmine.any(Number)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
Clone travel: Clonar envío
|
Clone travel: Clonar envío
|
||||||
|
Clone travel and his entries: Clonar travel y sus entradas
|
||||||
|
Do you want to clone this travel and all containing entries?: ¿Quieres clonar este travel y todas las entradas que contiene?
|
|
@ -13,7 +13,7 @@ Received: Recibido
|
||||||
Travel id: Id envío
|
Travel id: Id envío
|
||||||
Search travels by id: Buscar envíos por identificador
|
Search travels by id: Buscar envíos por identificador
|
||||||
New travel: Nuevo envío
|
New travel: Nuevo envío
|
||||||
travel: envio
|
travel: envío
|
||||||
|
|
||||||
# Sections
|
# Sections
|
||||||
Travels: Envíos
|
Travels: Envíos
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<vn-icon-button icon="launch"></vn-icon-button>
|
<vn-icon-button icon="launch"></vn-icon-button>
|
||||||
</a>
|
</a>
|
||||||
<span>{{$ctrl.travelData.id}} - {{$ctrl.travelData.ref}}</span>
|
<span>{{$ctrl.travelData.id}} - {{$ctrl.travelData.ref}}</span>
|
||||||
|
<vn-travel-descriptor-menu travel-id="$ctrl.travel.id"/>
|
||||||
</h5>
|
</h5>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-one>
|
<vn-one>
|
||||||
|
|
Loading…
Reference in New Issue