#794 item.regularize

This commit is contained in:
Gerard 2018-11-12 13:12:25 +01:00
parent 2820b29ba0
commit e55971a21a
32 changed files with 326 additions and 31 deletions

View File

@ -3,10 +3,19 @@
<a translate-attr="{title: 'Return to module index'}" ui-sref="item.index">
<vn-icon icon="chevron_left"></vn-icon>
</a>
<vn-icon icon="inbox"></vn-icon>
<a translate-attr="{title: 'Preview'}" ui-sref="item.card.summary({id: $ctrl.item.id})">
<vn-icon icon="desktop_windows"></vn-icon>
</a>
<vn-icon-menu
vn-id="more-button"
icon="more_vert"
show-filter="false"
value-field="callback"
translate-fields="['name']"
data="$ctrl.moreOptions"
on-change="$ctrl.onMoreChange(value)"
on-open="$ctrl.onMoreOpen()">
</vn-icon-menu>
</vn-horizontal>
<vn-vertical>
<vn-auto style="position: relative" text-center>
@ -75,3 +84,37 @@
</a>
</vn-horizontal>
</vn-card>
<vn-dialog
vn-id="regularize"
on-open="$ctrl.clearRegularizeDialog()"
on-response="$ctrl.saveRegularize(response)">
<tpl-body>
<div>
<h5 style="text-align: center">
<span translate>Regularize</span>
</h5>
<vn-textfield
label="Quantity"
model="$ctrl.quantity"
name="user"
vn-id="userField"
vn-focus>
</vn-textfield>
<vn-autocomplete
vn-one
label="Warehouse"
id="warehouse"
field="$ctrl.warehouseFk"
url="/api/Warehouses"
select-fields="['id', 'name']"
show-field="name"
value-field="id">
</vn-autocomplete>
</div>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Save</button>
</tpl-buttons>
</vn-dialog>

View File

@ -2,8 +2,42 @@ import ngModule from '../module';
import './style.scss';
class Controller {
constructor($state) {
constructor($state, $scope, $http, vnApp, $translate) {
this.$state = $state;
this.$scope = $scope;
this.$http = $http;
this.vnApp = vnApp;
this.$translate = $translate;
this.moreOptions = [
{callback: this.showRegularizeDialog, name: 'Regularize'}
];
}
set quantity(value) {
this._quantity = parseInt(value);
}
get quantity() {
return this._quantity;
}
set warehouseFk(value) {
this._warehouseFk = value;
}
get warehouseFk() {
if (!this._warehouseFk)
this._warehouseFk = parseInt(window.localStorage.localWarehouseFk);
return this._warehouseFk;
}
onMoreChange(callback) {
callback.call(this);
}
showRegularizeDialog() {
this.$scope.regularize.show();
}
set quicklinks(value = {}) {
@ -13,9 +47,26 @@ class Controller {
get quicklinks() {
return this._quicklinks;
}
saveRegularize(response) {
if (response == 'ACCEPT') {
this.$http.post(`/item/api/Items/regularize`, {
itemFk: this.item.id,
quantity: this.quantity,
warehouseFk: this.warehouseFk
}).then(res => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
});
}
}
Controller.$inject = ['$state'];
clearRegularizeDialog() {
this.warehouseFk = null;
this.quantity = null;
}
}
Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate'];
ngModule.component('vnItemDescriptor', {
template: require('./index.html'),

View File

@ -0,0 +1 @@
Regularize: Regularizar

View File

@ -6,4 +6,9 @@ vn-item-descriptor {
height: 100%;
width: 100%;
}
vn-dialog[vn-id=regularize]{
vn-textfield{
width: 100%
}
}
}

View File

@ -11,9 +11,6 @@
"ClaimRedelivery": {
"dataSource": "vn"
},
"ClaimDestination": {
"dataSource": "vn"
},
"ClaimResponsible": {
"dataSource": "vn"
},

View File

@ -0,0 +1,119 @@
module.exports = Self => {
Self.remoteMethodCtx('regularize', {
description: 'Sends items to the trash',
accessType: 'WRITE',
accepts: [{
arg: 'itemFk',
type: 'number',
required: true,
description: 'The item id',
}, {
arg: 'quantity',
type: 'number',
required: true,
description: 'The visible quantity',
}, {
arg: 'warehouseFk',
type: 'number',
required: true,
description: 'The id of the wharehouse where the inventory happened',
}],
returns: {
type: 'boolean',
root: true
},
http: {
path: `/regularize`,
verb: 'post'
}
});
Self.regularize = async (ctx, itemFk, quantity, warehouseFk) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const itemDestination = await models.ClaimDestination.findOne({
include: {
relation: 'address',
scope: {
fields: ['clientFk']
}
},
where: {description: 'Corregido'}
});
let transaction = await Self.beginTransaction({});
try {
let item = await models.Item.findById(itemFk);
let ticketFk = await getTicketId({
clientFk: itemDestination.address.clientFk,
addressFk: itemDestination.addressFk,
warehouseFk: warehouseFk
}, transaction);
if (!ticketFk) {
ticketFk = await createTicket({
clientFk: itemDestination.address().clientFk,
addressFk: itemDestination.addressFk,
warehouseFk: warehouseFk,
userId: userId
}, transaction);
}
let query = `
CALL vn.getItemVisibleAvailable(?,curdate(),?,?)`;
let options = [itemFk, warehouseFk, true];
let [res] = await Self.rawSql(query, options, {transaction: transaction});
let newQuantity = res[0].visible - quantity;
await models.Sale.create({
ticketFk: ticketFk,
itemFk: itemFk,
concept: item.name,
quantity: newQuantity,
discount: 100
}, {transaction: transaction});
await transaction.commit();
return ticketFk;
} catch (e) {
await transaction.rollback();
throw e;
}
async function createTicket(params, transaction) {
let ticket = await Self.app.models.Ticket.new({
shipped: new Date(),
landed: new Date(),
clientFk: params.clientFk,
warehouseFk: params.warehouseFk,
companyFk: params.companyFk,
addressFk: params.addressFk,
userId: params.userId
}, {transaction: transaction});
return ticket.id;
}
async function getTicketId(params, transaction) {
const currentDate = new Date();
currentDate.setHours(null, null, null);
let ticket = await Self.app.models.Ticket.findOne({
where: {
addressFk: params.addressFk,
warehouseFk: params.warehouseFk,
shipped: currentDate,
landed: currentDate
}
}, {transaction: transaction});
return ticket && ticket.id;
}
};
};

View File

@ -0,0 +1,33 @@
const app = require(`${servicesDir}/item/server/server`);
describe('regularize()', () => {
const itemFk = 1;
const warehouseFk = 1;
const trashAddress = 11;
let trashTicket;
afterAll(async () => {
await app.models.Ticket.destroyById(trashTicket.id);
});
it('should create a new ticket and add a line', async () => {
let ctx = {req: {accessToken: {userId: 18}}};
let query = `CALL vn.getItemVisibleAvailable(?,curdate(),?,?)`;
let options = [itemFk, warehouseFk, true];
let [res] = await app.models.Item.rawSql(query, options);
let visible = res[0].visible;
let saleQuantity = visible - 11;
let ticketFk = await app.models.Item.regularize(ctx, itemFk, 11, warehouseFk);
let sale = await app.models.Sale.findOne({where: {ticketFk: ticketFk}});
trashTicket = await app.models.Ticket.findById(ticketFk);
expect(sale.quantity).toEqual(saleQuantity);
expect(sale.discount).toEqual(100);
expect(trashTicket.addressFk).toEqual(trashAddress);
});
});

View File

@ -1,4 +1,4 @@
const ParameterizedSQL = require('vn-loopback/node_modules/loopback-connector').ParameterizedSQL;
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('catalogFilter', {
@ -61,14 +61,14 @@ module.exports = Self => {
for (const tag of tags) {
const tAlias = `it${i++}`;
if (tag.tagFk)
if (tag.tagFk) {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.tagFk = ?
AND ${tAlias}.value LIKE ?`,
params: [tag.tagFk, `%${tag.value}%`],
});
else
} else {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.value LIKE ?`,
@ -76,6 +76,7 @@ module.exports = Self => {
});
}
}
}
stmt.merge(conn.makeWhere(filter.where));
stmts.push(stmt);

View File

@ -1,4 +1,4 @@
const UserError = require('vn-loopback/common/helpers').UserError;
let UserError = require('../../helpers').UserError;
module.exports = Self => {
Self.remoteMethod('new', {
@ -22,7 +22,7 @@ module.exports = Self => {
Self.new = async params => {
let address = await Self.app.models.Address.findOne({
where: {id: params.addressFk},
fields: 'clientFk'
fields: ['clientFk']
});
let clientFk = address.clientFk;
@ -51,7 +51,7 @@ module.exports = Self => {
params.landed,
params.agencyModeFk,
params.addressFk,
"SALIX"
'SALIX'
]);
return result[0].vOrderId;

View File

@ -0,0 +1,34 @@
module.exports = Self => {
Self.remoteMethod('newFromTicket', {
description: 'Create a new order and returns the new ID',
accessType: 'WRITE',
accepts: [{
arg: 'ticketFk',
type: 'number',
description: 'The ticket id',
required: true
}],
returns: {
type: 'number',
root: true
},
http: {
path: `/newFromTicket`,
verb: 'post'
}
});
Self.newFromTicket = async ticketFk => {
let ticket = await Self.app.models.Ticket.findOne({
where: {id: ticketFk}
});
let orderID = await Self.app.models.Order.new({
addressFk: ticket.addressFk,
landed: ticket.landed,
agencyModeFk: ticket.agencyModeFk
});
return orderID;
};
};

View File

@ -1,5 +1,5 @@
const app = require(`${servicesDir}/order/server/server`);
const UserError = require('vn-loopback/common/helpers').UserError;
let UserError = require('../../../helpers').UserError;
describe('order new()', () => {
let orderId;

View File

@ -8,6 +8,7 @@ module.exports = Self => {
require('../methods/item/getLastEntries')(Self);
require('../methods/item/getSummary')(Self);
require('../methods/item/getCard')(Self);
require('../methods/item/regularize')(Self);
Self.validatesPresenceOf('name', {message: 'Cannot be blank'});
Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'});

View File

@ -9,4 +9,5 @@ module.exports = Self => {
require('../methods/order/summary')(Self);
require('../methods/order/getVAT')(Self);
require('../methods/order/getSourceValues')(Self);
require('../methods/order/newFromTicket')(Self);
};

View File

@ -152,5 +152,14 @@
},
"TicketRequest": {
"dataSource": "vn"
},
"TicketLog": {
"dataSource": "vn"
},
"ClaimDestination": {
"dataSource": "vn"
},
"Order": {
"dataSource": "hedera"
}
}