Merge pull request '5561-ticket.sale-tracking_cambiandoCrudModel' (!1614) from 5561-ticket.sale-tracking_cambiandoCrudModel into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #1614 Reviewed-by: Juan Ferrer <juan@verdnatura.es> Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
9479b1931f
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('SaleTracking', 'deleteSaleGroupDetail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('SaleTracking', 'replaceOrCreate', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,7 @@
|
||||||
|
DELETE FROM `vn`.`saleGroupDetail` WHERE id IN (468106,468104,468107,468105,495210,495208,495207,495209,462879,462880,447186,450623,450622,455606,455605,455827,455829,455828,459067,460689,460691,460690,460692,462408,463403,463405,463404,463129,463127,463126,463128,468098,468096,468099,468097,468310,468314,468313,475654,468325,473248,474803,474739,475042,475052,475047,475041,475051,475046,475040,475050,475045,475039,475049,475044,475038,475048,475043,474888,474892,474890,474887,474891,474889,481109,481107,481105,481108,481106,481110,479008,490787,490792,490791,485295,485294,485293,485528,490796,487853,487959,491303,490789,490914,490913,492305,492310,492307,492304,492309,492306,492303,492308,494111,494110,494480,494482,494481,494483,495202,495200,495199,495201,497209,499765,499763,499767,499764,499768,499766,502014,502013,508820,508819,508818,463133,463131,463130,463132,468102,468100,468103,468101,468311,468316,468315,468327,474894,474898,474896,474893,474897,474895,495206,495204,495203,495205,499771,499769,499773,499770,499774,499772);
|
||||||
|
ALTER TABLE `vn`.`saleGroupDetail` ADD CONSTRAINT saleGroupDetail_UN UNIQUE KEY (saleFk);
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||||
|
VALUES
|
||||||
|
('SaleGroupDetail','deleteById','WRITE','ALLOW','employee');
|
||||||
|
|
|
@ -28,11 +28,15 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const stmt = new ParameterizedSQL(`
|
const stmt = new ParameterizedSQL(`
|
||||||
SELECT iss.created,
|
SELECT
|
||||||
|
iss.id,
|
||||||
|
iss.created,
|
||||||
iss.saleFk,
|
iss.saleFk,
|
||||||
iss.quantity,
|
iss.quantity,
|
||||||
iss.userFk,
|
iss.userFk,
|
||||||
|
ish.id itemShelvingFk,
|
||||||
ish.shelvingFk,
|
ish.shelvingFk,
|
||||||
|
s.parkingFk,
|
||||||
p.code,
|
p.code,
|
||||||
u.name
|
u.name
|
||||||
FROM itemShelvingSale iss
|
FROM itemShelvingSale iss
|
||||||
|
|
|
@ -41,11 +41,6 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "VnUser",
|
"model": "VnUser",
|
||||||
"foreignKey": "userFk"
|
"foreignKey": "userFk"
|
||||||
},
|
|
||||||
"shelving": {
|
|
||||||
"type": "belongsTo",
|
|
||||||
"model": "Shelving",
|
|
||||||
"foreignKey": "shelvingFk"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('delete', {
|
||||||
|
description: 'Delete sale trackings and item shelving sales',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'saleFk',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The sale id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'stateCode',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/delete`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.delete = async(saleFk, stateCode, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const myOptions = {};
|
||||||
|
let tx;
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
if (!myOptions.transaction) {
|
||||||
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (stateCode === 'PREPARED') {
|
||||||
|
const itemShelvingSales = await models.ItemShelvingSale.find({where: {saleFk: saleFk}}, myOptions);
|
||||||
|
for (let itemShelvingSale of itemShelvingSales)
|
||||||
|
await itemShelvingSale.destroy(myOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = await models.State.findOne({
|
||||||
|
where: {code: stateCode}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
where: {
|
||||||
|
saleFk: saleFk,
|
||||||
|
stateFk: state.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const saleTrackings = await models.SaleTracking.find(filter, myOptions);
|
||||||
|
for (let saleTracking of saleTrackings)
|
||||||
|
await saleTracking.destroy(myOptions);
|
||||||
|
|
||||||
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,94 @@
|
||||||
|
|
||||||
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('filter', {
|
||||||
|
description: 'Returns a list with the lines of a ticket and its different states of preparation',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The ticket id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object',
|
||||||
|
description: 'Filter defining where and paginated data'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/filter`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.filter = async(id, filter, options) => {
|
||||||
|
const conn = Self.dataSource.connector;
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const stmts = [];
|
||||||
|
let stmt;
|
||||||
|
|
||||||
|
stmts.push('CALL cache.last_buy_refresh(FALSE)');
|
||||||
|
|
||||||
|
stmt = new ParameterizedSQL(
|
||||||
|
`SELECT t.clientFk,
|
||||||
|
t.shipped,
|
||||||
|
s.ticketFk,
|
||||||
|
s.itemFk,
|
||||||
|
s.quantity,
|
||||||
|
s.concept,
|
||||||
|
s.id saleFk,
|
||||||
|
i.image,
|
||||||
|
i.subName,
|
||||||
|
IF(stPrevious.saleFk,TRUE,FALSE) as isPreviousSelected,
|
||||||
|
stPrevious.isChecked as isPrevious,
|
||||||
|
stPrepared.isChecked as isPrepared,
|
||||||
|
stControled.isChecked as isControled,
|
||||||
|
sgd.id saleGroupDetailFk,
|
||||||
|
(MAX(sgd.id) IS NOT NULL) AS hasSaleGroupDetail,
|
||||||
|
p.code AS parkingCode,
|
||||||
|
i.value5,
|
||||||
|
i.value6,
|
||||||
|
i.value7,
|
||||||
|
i.value8,
|
||||||
|
i.value9,
|
||||||
|
i.value10
|
||||||
|
FROM vn.ticket t
|
||||||
|
JOIN vn.sale s ON s.ticketFk = t.id
|
||||||
|
JOIN vn.item i ON i.id = s.itemFk
|
||||||
|
LEFT JOIN cache.last_buy lb ON lb.item_id = i.id AND lb.warehouse_id = t.warehouseFk
|
||||||
|
LEFT JOIN vn.state st ON TRUE
|
||||||
|
LEFT JOIN vn.saleTracking stPrevious ON stPrevious.saleFk = s.id
|
||||||
|
AND stPrevious.stateFk = (SELECT id FROM vn.state WHERE code = 'PREVIOUS_PREPARATION')
|
||||||
|
LEFT JOIN vn.saleTracking stPrepared ON stPrepared.saleFk = s.id
|
||||||
|
AND stPrepared.stateFk = (SELECT id FROM vn.state WHERE code = 'PREPARED')
|
||||||
|
LEFT JOIN vn.saleTracking stControled ON stControled.saleFk = s.id
|
||||||
|
AND stControled.stateFk = (SELECT id FROM vn.state s2 WHERE code = 'CHECKED')
|
||||||
|
LEFT JOIN vn.saleGroupDetail sgd ON sgd.saleFk = s.id
|
||||||
|
LEFT JOIN vn.saleGroup sg ON sg.id = sgd.saleGroupFk
|
||||||
|
LEFT JOIN vn.parking p ON p.id = sg.parkingFk
|
||||||
|
WHERE t.id = ?
|
||||||
|
GROUP BY s.id`, [id]);
|
||||||
|
|
||||||
|
stmts.push(stmt);
|
||||||
|
|
||||||
|
stmt.merge(Self.makeSuffix(filter));
|
||||||
|
|
||||||
|
const index = stmts.push(stmt) - 1;
|
||||||
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
|
const result = await conn.executeStmt(sql, myOptions);
|
||||||
|
|
||||||
|
return result[index];
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('new', {
|
||||||
|
description: `Replaces the record or creates it if it doesn't exist`,
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'saleFk',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The sale id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'isChecked',
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'quantity',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'stateCode',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/new`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.new = async(ctx, saleFk, isChecked, quantity, stateCode, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const myOptions = {};
|
||||||
|
let tx;
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
if (!myOptions.transaction) {
|
||||||
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const state = await models.State.findOne({
|
||||||
|
where: {code: stateCode}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
const saleTracking = await models.SaleTracking.findOne({
|
||||||
|
where: {
|
||||||
|
saleFk: saleFk,
|
||||||
|
stateFk: state.id,
|
||||||
|
workerFk: userId
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
let newSaleTracking;
|
||||||
|
if (saleTracking) {
|
||||||
|
newSaleTracking = await saleTracking.updateAttributes({
|
||||||
|
saleFk: saleFk,
|
||||||
|
stateFk: state.id,
|
||||||
|
workerFk: userId,
|
||||||
|
isChecked: isChecked,
|
||||||
|
originalQuantity: quantity,
|
||||||
|
isScanned: null
|
||||||
|
}, myOptions);
|
||||||
|
} else {
|
||||||
|
newSaleTracking = await models.SaleTracking.create({
|
||||||
|
saleFk: saleFk,
|
||||||
|
stateFk: state.id,
|
||||||
|
workerFk: userId,
|
||||||
|
isChecked: isChecked,
|
||||||
|
originalQuantity: quantity,
|
||||||
|
isScanned: null
|
||||||
|
}, myOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
|
return newSaleTracking;
|
||||||
|
} catch (e) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('sale-tracking delete()', () => {
|
||||||
|
it('should delete a row of saleTracking and itemShelvingSale', async() => {
|
||||||
|
const tx = await models.SaleTracking.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const itemShelvingsBefore = await models.ItemShelvingSale.find(null, options);
|
||||||
|
const saleTrackingsBefore = await models.SaleTracking.find(null, options);
|
||||||
|
|
||||||
|
const saleFk = 1;
|
||||||
|
const stateCode = 'PREPARED';
|
||||||
|
const result = await models.SaleTracking.delete(saleFk, stateCode, options);
|
||||||
|
|
||||||
|
const itemShelvingsAfter = await models.ItemShelvingSale.find(null, options);
|
||||||
|
const saleTrackingsAfter = await models.SaleTracking.find(null, options);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
expect(saleTrackingsAfter.length).toBeLessThan(saleTrackingsBefore.length);
|
||||||
|
expect(itemShelvingsAfter.length).toBeLessThan(itemShelvingsBefore.length);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('sale-tracking filter()', () => {
|
||||||
|
it('should return 1 result filtering by ticket id', async() => {
|
||||||
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const id = 1;
|
||||||
|
const filter = {order: ['concept ASC', 'quantity DESC']};
|
||||||
|
const result = await app.models.SaleTracking.filter(id, filter, options);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(4);
|
||||||
|
expect(result[0].ticketFk).toEqual(1);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('ticket listSaleTracking()', () => {
|
describe('sale-tracking listSaleTracking()', () => {
|
||||||
it('should call the listSaleTracking method and return the response', async() => {
|
it('should call the listSaleTracking method and return the response', async() => {
|
||||||
const tx = await models.SaleTracking.beginTransaction({});
|
const tx = await models.SaleTracking.beginTransaction({});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('sale-tracking new()', () => {
|
||||||
|
it('should update a saleTracking', async() => {
|
||||||
|
const tx = await models.SaleTracking.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const ctx = {req: {accessToken: {userId: 55}}};
|
||||||
|
|
||||||
|
const saleFk = 1;
|
||||||
|
const isChecked = true;
|
||||||
|
const quantity = 20;
|
||||||
|
const stateCode = 'PREPARED';
|
||||||
|
const result = await models.SaleTracking.new(ctx, saleFk, isChecked, quantity, stateCode, options);
|
||||||
|
|
||||||
|
expect(result.isChecked).toBe(true);
|
||||||
|
expect(result.originalQuantity).toBe(20);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a saleTracking', async() => {
|
||||||
|
const tx = await models.SaleTracking.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
|
|
||||||
|
const saleFk = 1;
|
||||||
|
const isChecked = true;
|
||||||
|
const quantity = 20;
|
||||||
|
const stateCode = 'PREPARED';
|
||||||
|
const result = await models.SaleTracking.new(ctx, saleFk, isChecked, quantity, stateCode, options);
|
||||||
|
|
||||||
|
expect(result.isChecked).toBe(true);
|
||||||
|
expect(result.originalQuantity).toBe(20);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,33 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethodCtx('salePreparingList', {
|
|
||||||
description: 'Returns a list with the lines of a ticket and its different states of preparation',
|
|
||||||
accessType: 'READ',
|
|
||||||
accepts: [{
|
|
||||||
arg: 'id',
|
|
||||||
type: 'number',
|
|
||||||
required: true,
|
|
||||||
description: 'The ticket id',
|
|
||||||
http: {source: 'path'}
|
|
||||||
}],
|
|
||||||
returns: {
|
|
||||||
type: ['object'],
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/:id/salePreparingList`,
|
|
||||||
verb: 'GET'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.salePreparingList = async(ctx, id, options) => {
|
|
||||||
const myOptions = {};
|
|
||||||
|
|
||||||
if (typeof options == 'object')
|
|
||||||
Object.assign(myOptions, options);
|
|
||||||
|
|
||||||
query = `CALL vn.salePreparingList(?)`;
|
|
||||||
const [sales] = await Self.rawSql(query, [id], myOptions);
|
|
||||||
|
|
||||||
return sales;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,3 +1,6 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
require('../methods/sale-tracking/filter')(Self);
|
||||||
require('../methods/sale-tracking/listSaleTracking')(Self);
|
require('../methods/sale-tracking/listSaleTracking')(Self);
|
||||||
|
require('../methods/sale-tracking/new')(Self);
|
||||||
|
require('../methods/sale-tracking/delete')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/sale/getClaimableFromTicket')(Self);
|
require('../methods/sale/getClaimableFromTicket')(Self);
|
||||||
require('../methods/sale/salePreparingList')(Self);
|
|
||||||
require('../methods/sale/reserve')(Self);
|
require('../methods/sale/reserve')(Self);
|
||||||
require('../methods/sale/deleteSales')(Self);
|
require('../methods/sale/deleteSales')(Self);
|
||||||
require('../methods/sale/updatePrice')(Self);
|
require('../methods/sale/updatePrice')(Self);
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
vn-id="model"
|
vn-id="model"
|
||||||
url="sales"
|
url="SaleTrackings/{{$ctrl.$params.id}}/filter"
|
||||||
filter="::$ctrl.filter"
|
|
||||||
link="{ticketFk: $ctrl.$params.id}"
|
|
||||||
limit="20"
|
limit="20"
|
||||||
data="$ctrl.sales"
|
data="$ctrl.sales"
|
||||||
order="concept ASC"
|
order="concept ASC, quantity DESC"
|
||||||
|
auto-load="true">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-crud-model
|
||||||
|
url="Shelvings"
|
||||||
|
data="shelvings"
|
||||||
|
auto-load="true">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-crud-model
|
||||||
|
url="Parkings"
|
||||||
|
data="parkings"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-data-viewer model="model">
|
<vn-data-viewer model="model">
|
||||||
|
@ -13,7 +21,7 @@
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="isChecked" center>Is checked</vn-th>
|
<vn-th field="isChecked" center expand>Is checked</vn-th>
|
||||||
<vn-th field="itemFk" number>Item</vn-th>
|
<vn-th field="itemFk" number>Item</vn-th>
|
||||||
<vn-th field="concept">Description</vn-th>
|
<vn-th field="concept">Description</vn-th>
|
||||||
<vn-th field="quantity" number>Quantity</vn-th>
|
<vn-th field="quantity" number>Quantity</vn-th>
|
||||||
|
@ -23,76 +31,84 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.sales">
|
<vn-tr ng-repeat="sale in $ctrl.sales">
|
||||||
<vn-td center>
|
<vn-td center expand>
|
||||||
<vn-chip
|
<vn-chip
|
||||||
ng-class="::{
|
ng-class="{
|
||||||
'pink': sale.preparingList.hasSaleGroupDetail,
|
'pink': sale.hasSaleGroupDetail,
|
||||||
'none': !sale.preparingList.hasSaleGroupDetail,
|
'none': !sale.hasSaleGroupDetail,
|
||||||
}"
|
}"
|
||||||
class="circleState"
|
class="circleState"
|
||||||
vn-tooltip="has saleGroupDetail"
|
vn-tooltip="sale group detail"
|
||||||
>
|
vn-click-stop="$ctrl.clickSaleGroupDetail($index)">
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
<vn-chip ng-class="::{
|
<vn-chip
|
||||||
'notice': sale.preparingList.isPreviousSelected,
|
ng-class="{
|
||||||
'none': !sale.preparingList.isPreviousSelected,
|
'notice': sale.isPreviousSelected,
|
||||||
}"
|
'none': !sale.isPreviousSelected,
|
||||||
class="circleState"
|
}"
|
||||||
vn-tooltip="is previousSelected">
|
class="circleState"
|
||||||
|
vn-tooltip="previous selected"
|
||||||
|
vn-click-stop="$ctrl.clickPreviousSelected($index)">
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
<vn-chip ng-class="::{
|
<vn-chip
|
||||||
'dark-notice': sale.preparingList.isPrevious,
|
ng-class="{
|
||||||
'none': !sale.preparingList.isPrevious,
|
'dark-notice': sale.isPrevious,
|
||||||
}"
|
'none': !sale.isPrevious,
|
||||||
class="circleState"
|
}"
|
||||||
vn-tooltip="is previous">
|
class="circleState"
|
||||||
|
vn-tooltip="previous"
|
||||||
|
vn-click-stop="$ctrl.clickPrevious($index)">
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
<vn-chip ng-class="::{
|
<vn-chip
|
||||||
'warning': sale.preparingList.isPrepared,
|
ng-class="{
|
||||||
'none': !sale.preparingList.isPrepared,
|
'warning': sale.isPrepared,
|
||||||
}"
|
'none': !sale.isPrepared,
|
||||||
class="circleState"
|
}"
|
||||||
vn-tooltip="is prepared">
|
class="circleState"
|
||||||
|
vn-tooltip="prepared"
|
||||||
|
vn-click-stop="$ctrl.clickPrepared($index)">
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
<vn-chip ng-class="::{
|
<vn-chip
|
||||||
'yellow': sale.preparingList.isControled,
|
ng-class="{
|
||||||
'none': !sale.preparingList.isControled,
|
'yellow': sale.isControled,
|
||||||
}"
|
'none': !sale.isControled,
|
||||||
class="circleState"
|
}"
|
||||||
vn-tooltip="is controled">
|
class="circleState"
|
||||||
|
vn-tooltip="checked"
|
||||||
|
vn-click-stop="$ctrl.clickControled($index)">
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, sale.item.id)"
|
ng-click="itemDescriptor.show($event, sale.itemFk)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::sale.item.id}}
|
{{::sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
<div>
|
<div>
|
||||||
<vn-one title="{{::sale.item.name}}">{{::sale.item.name}}</vn-one>
|
<vn-one title="{{::sale.concept}}">{{::sale.concept}}</vn-one>
|
||||||
<vn-one ng-if="::sale.item.subName">
|
<vn-one ng-if="::sale.subName">
|
||||||
<h3 title="{{::sale.item.subName}}">{{::sale.item.subName}}</h3>
|
<h3 title="{{::sale.subName}}">{{::sale.subName}}</h3>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</div>
|
</div>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="::sale.item"
|
item="::sale"
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||||
<vn-td center>{{::sale.saleGroupDetail.saleGroup.parking.code | dashIfEmpty}}</vn-td>
|
<vn-td center>{{::sale.parkingCode | dashIfEmpty}}</vn-td>
|
||||||
<vn-td actions>
|
<vn-td actions>
|
||||||
<vn-icon-button
|
<vn-icon-button
|
||||||
vn-click-stop="$ctrl.showSaleTracking(sale)"
|
vn-click-stop="$ctrl.showSaleTracking(sale)"
|
||||||
vn-tooltip="Sale tracking"
|
vn-tooltip="Log states"
|
||||||
icon="history">
|
icon="history">
|
||||||
</vn-icon-button>
|
</vn-icon-button>
|
||||||
<vn-icon-button
|
<vn-icon-button
|
||||||
vn-click-stop="$ctrl.showItemShelvingSale(sale)"
|
vn-click-stop="$ctrl.showItemShelvingSale(sale)"
|
||||||
vn-tooltip="ItemShelvings sale"
|
vn-tooltip="Shelvings sale"
|
||||||
icon="icon-inventory">
|
icon="icon-inventory">
|
||||||
</vn-icon-button>
|
</vn-icon-button>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
|
@ -154,28 +170,35 @@
|
||||||
|
|
||||||
<vn-popup vn-id="itemShelvingSale">
|
<vn-popup vn-id="itemShelvingSale">
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
vn-id="modelSaleTracking"
|
vn-id="modelItemShelvingSale"
|
||||||
url="ItemShelvingSales/filter"
|
url="ItemShelvingSales/filter"
|
||||||
link="{saleFk: $ctrl.saleId}"
|
link="{saleFk: $ctrl.saleId}"
|
||||||
limit="20"
|
limit="20"
|
||||||
data="$ctrl.itemShelvingSales"
|
data="$ctrl.itemShelvingSales"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-data-viewer model="modelSaleTracking">
|
<vn-data-viewer model="modelItemShelvingSale" class="vn-w-lg">
|
||||||
<vn-card class="vn-w-lg">
|
<vn-table>
|
||||||
<vn-table model="modelSaleTracking">
|
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="quantity" number>Quantity</vn-th>
|
<vn-th field="quantity" number>Quantity</vn-th>
|
||||||
<vn-th field="workerFk">Worker</vn-th>
|
<vn-th field="workerFk">Worker</vn-th>
|
||||||
<vn-th field="shelving" shrink>Shelving</vn-th>
|
<vn-th field="shelving" expand>Shelving</vn-th>
|
||||||
<vn-th field="parking" shrink>Parking</vn-th>
|
<vn-th field="parking" expand>Parking</vn-th>
|
||||||
<vn-th field="created" expand>Created</vn-th>
|
<vn-th field="created" expand>Created</vn-th>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="itemShelvingSale in $ctrl.itemShelvingSales">
|
<vn-tr ng-repeat="itemShelvingSale in $ctrl.itemShelvingSales">
|
||||||
<vn-td number>{{::itemShelvingSale.quantity}}</vn-td>
|
<vn-td-editable number shrink>
|
||||||
|
<text>{{itemShelvingSale.quantity}}</text>
|
||||||
|
<field>
|
||||||
|
<vn-input-number class="dense" vn-focus
|
||||||
|
ng-model="itemShelvingSale.quantity"
|
||||||
|
on-change="$ctrl.updateQuantity(itemShelvingSale)">
|
||||||
|
</vn-input-number>
|
||||||
|
</field>
|
||||||
|
</vn-td-editable>
|
||||||
<vn-td expand>
|
<vn-td expand>
|
||||||
<span
|
<span
|
||||||
class="link"
|
class="link"
|
||||||
|
@ -183,8 +206,24 @@
|
||||||
{{::itemShelvingSale.name | dashIfEmpty}}
|
{{::itemShelvingSale.name | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>{{::itemShelvingSale.shelvingFk}}</vn-td>
|
<vn-td expand>
|
||||||
<vn-td shrink>{{::itemShelvingSale.code}}</vn-td>
|
<vn-autocomplete
|
||||||
|
data="shelvings"
|
||||||
|
show-field="code"
|
||||||
|
value-field="code"
|
||||||
|
ng-model="itemShelvingSale.shelvingFk"
|
||||||
|
on-change="$ctrl.updateShelving(itemShelvingSale)">
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-td>
|
||||||
|
<vn-td expand>
|
||||||
|
<vn-autocomplete
|
||||||
|
data="parkings"
|
||||||
|
show-field="code"
|
||||||
|
value-field="id"
|
||||||
|
ng-model="itemShelvingSale.parkingFk"
|
||||||
|
on-change="$ctrl.updateParking(itemShelvingSale)">
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-td>
|
||||||
<vn-td expand>{{::itemShelvingSale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
<vn-td expand>{{::itemShelvingSale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
|
|
|
@ -3,62 +3,6 @@ import Section from 'salix/components/section';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
class Controller extends Section {
|
class Controller extends Section {
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'item'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'saleTracking',
|
|
||||||
scope: {
|
|
||||||
fields: ['isChecked']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'saleGroupDetail',
|
|
||||||
scope: {
|
|
||||||
fields: ['saleGroupFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'saleGroup',
|
|
||||||
scope: {
|
|
||||||
fields: ['parkingFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'parking',
|
|
||||||
scope: {
|
|
||||||
fields: ['code']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get sales() {
|
|
||||||
return this._sales;
|
|
||||||
}
|
|
||||||
|
|
||||||
set sales(value) {
|
|
||||||
this._sales = value;
|
|
||||||
if (value) {
|
|
||||||
const query = `Sales/${this.$params.id}/salePreparingList`;
|
|
||||||
this.$http.get(query)
|
|
||||||
.then(res => {
|
|
||||||
this.salePreparingList = res.data;
|
|
||||||
for (const salePreparing of this.salePreparingList) {
|
|
||||||
for (const sale of this.sales) {
|
|
||||||
if (salePreparing.saleFk == sale.id)
|
|
||||||
sale.preparingList = salePreparing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showItemDescriptor(event, sale) {
|
showItemDescriptor(event, sale) {
|
||||||
this.quicklinks = {
|
this.quicklinks = {
|
||||||
btnThree: {
|
btnThree: {
|
||||||
|
@ -75,20 +19,145 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
showSaleTracking(sale) {
|
showSaleTracking(sale) {
|
||||||
this.saleId = sale.id;
|
this.saleId = sale.saleFk;
|
||||||
this.$.saleTracking.show();
|
this.$.saleTracking.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
showItemShelvingSale(sale) {
|
showItemShelvingSale(sale) {
|
||||||
this.saleId = sale.id;
|
this.saleId = sale.saleFk;
|
||||||
this.$.itemShelvingSale.show();
|
this.$.itemShelvingSale.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clickSaleGroupDetail(index) {
|
||||||
|
const sale = this.sales[index];
|
||||||
|
if (!sale.saleGroupDetailFk) return;
|
||||||
|
|
||||||
|
return this.$http.delete(`SaleGroupDetails/${sale.saleGroupDetailFk}`)
|
||||||
|
.then(() => {
|
||||||
|
sale.hasSaleGroupDetail = false;
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clickPreviousSelected(index) {
|
||||||
|
const sale = this.sales[index];
|
||||||
|
if (!sale.isPreviousSelected) {
|
||||||
|
this.saleTrackingNew(sale, 'PREVIOUS_PREPARATION', false);
|
||||||
|
sale.isPreviousSelected = true;
|
||||||
|
} else {
|
||||||
|
this.saleTrackingDel(sale, 'PREVIOUS_PREPARATION');
|
||||||
|
sale.isPreviousSelected = false;
|
||||||
|
sale.isPrevious = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clickPrevious(index) {
|
||||||
|
const sale = this.sales[index];
|
||||||
|
if (!sale.isPrevious) {
|
||||||
|
this.saleTrackingNew(sale, 'PREVIOUS_PREPARATION', true);
|
||||||
|
sale.isPrevious = true;
|
||||||
|
sale.isPreviousSelected = true;
|
||||||
|
} else {
|
||||||
|
this.saleTrackingNew(sale, 'PREVIOUS_PREPARATION', false);
|
||||||
|
sale.isPrevious = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clickPrepared(index) {
|
||||||
|
const sale = this.sales[index];
|
||||||
|
if (!sale.isPrepared) {
|
||||||
|
this.saleTrackingNew(sale, 'PREPARED', true);
|
||||||
|
sale.isPrepared = true;
|
||||||
|
} else {
|
||||||
|
this.saleTrackingDel(sale, 'PREPARED');
|
||||||
|
sale.isPrepared = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clickControled(index) {
|
||||||
|
const sale = this.sales[index];
|
||||||
|
if (!sale.isControled) {
|
||||||
|
this.saleTrackingNew(sale, 'CHECKED', true);
|
||||||
|
sale.isControled = true;
|
||||||
|
} else {
|
||||||
|
this.saleTrackingDel(sale, 'CHECKED');
|
||||||
|
sale.isControled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saleTrackingNew(sale, stateCode, isChecked) {
|
||||||
|
const params = {
|
||||||
|
saleFk: sale.saleFk,
|
||||||
|
isChecked: isChecked,
|
||||||
|
quantity: sale.quantity,
|
||||||
|
stateCode: stateCode
|
||||||
|
};
|
||||||
|
this.$http.post(`SaleTrackings/new`, params).then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saleTrackingDel(sale, stateCode) {
|
||||||
|
const params = {
|
||||||
|
saleFk: sale.saleFk,
|
||||||
|
stateCode: stateCode
|
||||||
|
};
|
||||||
|
this.$http.post(`SaleTrackings/delete`, params).then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateQuantity(itemShelvingSale) {
|
||||||
|
const params = {
|
||||||
|
quantity: itemShelvingSale.quantity
|
||||||
|
};
|
||||||
|
this.$http.patch(`ItemShelvingSales/${itemShelvingSale.id}`, params)
|
||||||
|
.then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateShelving(itemShelvingSale) {
|
||||||
|
const params = {
|
||||||
|
shelvingFk: itemShelvingSale.shelvingFk
|
||||||
|
};
|
||||||
|
const res = await this.$http.patch(`ItemShelvings/${itemShelvingSale.itemShelvingFk}`, params);
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
fields: ['parkingFk'],
|
||||||
|
where: {
|
||||||
|
code: res.data.shelvingFk
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.$http.get(`Shelvings/findOne`, {filter})
|
||||||
|
.then(res => {
|
||||||
|
itemShelvingSale.parkingFk = res.data.parkingFk;
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateParking(itemShelvingSale) {
|
||||||
|
const filter = {
|
||||||
|
fields: ['id'],
|
||||||
|
where: {
|
||||||
|
code: itemShelvingSale.shelvingFk
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const res = await this.$http.get(`Shelvings/findOne`, {filter});
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
parkingFk: itemShelvingSale.parkingFk
|
||||||
|
};
|
||||||
|
this.$http.patch(`Shelvings/${res.data.id}`, params)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnTicketSaleTracking', {
|
ngModule.vnComponent('vnTicketSaleTracking', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
bindings: {
|
bindings: {
|
||||||
ticket: '<'
|
ticket: '<',
|
||||||
|
model: '<?'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
ItemShelvings sale: Carros línea
|
Shelvings sale: Carros línea
|
||||||
has saleGroupDetail: tiene detalle grupo lineas
|
Log states: Historial estados
|
||||||
is previousSelected: es previa seleccionada
|
sale group detail: detalle grupo lineas
|
||||||
is previous: es previa
|
previous selected: previa seleccionado
|
||||||
is prepared: esta preparado
|
previous: previa
|
||||||
is controled: esta controlado
|
prepared: preparado
|
||||||
|
checked: revisado
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
vn-sale-tracking {
|
|
||||||
.chip {
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 15px;
|
|
||||||
min-height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.circleState {
|
.circleState {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
Loading…
Reference in New Issue