Merge branch 'dev' into 4059-revocar-permisos-client-account
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
ec856c0db2
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -5,14 +5,23 @@ 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2326.01] - 2023-06-29
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## [2324.01] - 2023-06-08
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
- (Tickets -> Abono) Al abonar permite crear el ticket abono con almacén o sin almmacén
|
||||
- (General -> Desplegables) Mejorada eficiencia de carga de datos
|
||||
|
||||
### Changed
|
||||
-
|
||||
- (General -> Permisos) Mejorada seguridad
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
|
|
@ -11,9 +11,9 @@ RUN apt-get update \
|
|||
ca-certificates \
|
||||
gnupg2 \
|
||||
graphicsmagick \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& npm install -g npm@8.19.2
|
||||
&& npm install -g npm@9.6.6
|
||||
|
||||
# Puppeteer
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ pipeline {
|
|||
NODE_ENV = ""
|
||||
}
|
||||
steps {
|
||||
nodejs('node-v14') {
|
||||
nodejs('node-v20') {
|
||||
sh 'npm install --no-audit --prefer-offline'
|
||||
sh 'gulp install --ci'
|
||||
}
|
||||
|
@ -57,14 +57,14 @@ pipeline {
|
|||
parallel {
|
||||
stage('Frontend') {
|
||||
steps {
|
||||
nodejs('node-v14') {
|
||||
nodejs('node-v20') {
|
||||
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Backend') {
|
||||
steps {
|
||||
nodejs('node-v14') {
|
||||
nodejs('node-v20') {
|
||||
sh 'npm run test:back:ci'
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ pipeline {
|
|||
CREDENTIALS = credentials('docker-registry')
|
||||
}
|
||||
steps {
|
||||
nodejs('node-v14') {
|
||||
nodejs('node-v20') {
|
||||
sh 'gulp build'
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
DELIMITER $$
|
||||
$$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canAdvance`(vDateFuture DATE, vDateToAdvance DATE, vWarehouseFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
|
||||
*
|
||||
* @param vDateFuture Fecha de los tickets que se quieren adelantar.
|
||||
* @param vDateToAdvance Fecha a cuando se quiere adelantar.
|
||||
* @param vWarehouseFk Almacén
|
||||
*/
|
||||
|
||||
DECLARE vDateInventory DATE;
|
||||
|
||||
SELECT inventoried INTO vDateInventory FROM config;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.stock;
|
||||
CREATE TEMPORARY TABLE tmp.stock
|
||||
(itemFk INT PRIMARY KEY,
|
||||
amount INT)
|
||||
ENGINE = MEMORY;
|
||||
|
||||
INSERT INTO tmp.stock(itemFk, amount)
|
||||
SELECT itemFk, SUM(quantity) amount FROM
|
||||
(
|
||||
SELECT itemFk, quantity
|
||||
FROM itemTicketOut
|
||||
WHERE shipped >= vDateInventory
|
||||
AND shipped < vDateFuture
|
||||
AND warehouseFk = vWarehouseFk
|
||||
UNION ALL
|
||||
SELECT itemFk, quantity
|
||||
FROM itemEntryIn
|
||||
WHERE landed >= vDateInventory
|
||||
AND landed < vDateFuture
|
||||
AND isVirtualStock = FALSE
|
||||
AND warehouseInFk = vWarehouseFk
|
||||
UNION ALL
|
||||
SELECT itemFk, quantity
|
||||
FROM itemEntryOut
|
||||
WHERE shipped >= vDateInventory
|
||||
AND shipped < vDateFuture
|
||||
AND warehouseOutFk = vWarehouseFk
|
||||
) t
|
||||
GROUP BY itemFk HAVING amount != 0;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.filter;
|
||||
CREATE TEMPORARY TABLE tmp.filter
|
||||
(INDEX (id))
|
||||
SELECT
|
||||
origin.ticketFk futureId,
|
||||
dest.ticketFk id,
|
||||
dest.state,
|
||||
origin.futureState,
|
||||
origin.futureIpt,
|
||||
dest.ipt,
|
||||
origin.workerFk,
|
||||
origin.futureLiters,
|
||||
origin.futureLines,
|
||||
dest.shipped,
|
||||
origin.shipped futureShipped,
|
||||
dest.totalWithVat,
|
||||
origin.totalWithVat futureTotalWithVat,
|
||||
dest.agency,
|
||||
origin.futureAgency,
|
||||
dest.lines,
|
||||
dest.liters,
|
||||
origin.futureLines - origin.hasStock AS notMovableLines,
|
||||
(origin.futureLines = origin.hasStock) AS isFullMovable,
|
||||
origin.classColor futureClassColor,
|
||||
dest.classColor
|
||||
FROM (
|
||||
SELECT
|
||||
s.ticketFk,
|
||||
t.workerFk,
|
||||
t.shipped,
|
||||
t.totalWithVat,
|
||||
st.name futureState,
|
||||
t.addressFk,
|
||||
am.name futureAgency,
|
||||
count(s.id) futureLines,
|
||||
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) futureIpt,
|
||||
CAST(SUM(litros) AS DECIMAL(10,0)) futureLiters,
|
||||
SUM((s.quantity <= IFNULL(st.amount,0))) hasStock,
|
||||
st.classColor
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN state st ON st.id = ts.stateFk
|
||||
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||
LEFT JOIN tmp.stock st ON st.itemFk = i.id
|
||||
WHERE t.shipped BETWEEN vDateFuture AND util.dayend(vDateFuture)
|
||||
AND t.warehouseFk = vWarehouseFk
|
||||
GROUP BY t.id
|
||||
) origin
|
||||
JOIN (
|
||||
SELECT
|
||||
t.id ticketFk,
|
||||
t.addressFk,
|
||||
st.name state,
|
||||
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) ipt,
|
||||
t.shipped,
|
||||
t.totalWithVat,
|
||||
am.name agency,
|
||||
CAST(SUM(litros) AS DECIMAL(10,0)) liters,
|
||||
CAST(COUNT(*) AS DECIMAL(10,0)) `lines`,
|
||||
st.classColor
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN state st ON st.id = ts.stateFk
|
||||
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||
WHERE t.shipped BETWEEN vDateToAdvance AND util.dayend(vDateToAdvance)
|
||||
AND t.warehouseFk = vWarehouseFk
|
||||
AND st.order <= 5
|
||||
GROUP BY t.id
|
||||
) dest ON dest.addressFk = origin.addressFk
|
||||
WHERE origin.hasStock != 0;
|
||||
DROP TEMPORARY TABLE tmp.stock;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,74 @@
|
|||
DELIMITER $$
|
||||
$$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canbePostponed`(vOriginDated DATE, vFutureDated DATE, vWarehouseFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Devuelve un listado de tickets susceptibles de fusionarse con otros tickets en el futuro
|
||||
*
|
||||
* @param vOriginDated Fecha en cuestión
|
||||
* @param vFutureDated Fecha en el futuro a sondear
|
||||
* @param vWarehouseFk Identificador de vn.warehouse
|
||||
*/
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.filter;
|
||||
CREATE TEMPORARY TABLE tmp.filter
|
||||
(INDEX (id))
|
||||
SELECT sv.ticketFk id,
|
||||
sub2.id futureId,
|
||||
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
|
||||
CAST(sum(litros) AS DECIMAL(10,0)) liters,
|
||||
CAST(count(*) AS DECIMAL(10,0)) `lines`,
|
||||
st.name state,
|
||||
sub2.iptd futureIpt,
|
||||
sub2.state futureState,
|
||||
t.clientFk,
|
||||
t.warehouseFk,
|
||||
ts.alertLevel,
|
||||
t.shipped,
|
||||
sub2.shipped futureShipped,
|
||||
t.workerFk,
|
||||
st.code stateCode,
|
||||
sub2.code futureStateCode,
|
||||
st.classColor,
|
||||
sub2.classColor futureClassColor
|
||||
FROM vn.saleVolume sv
|
||||
JOIN vn.sale s ON s.id = sv.saleFk
|
||||
JOIN vn.item i ON i.id = s.itemFk
|
||||
JOIN vn.ticket t ON t.id = sv.ticketFk
|
||||
JOIN vn.address a ON a.id = t.addressFk
|
||||
JOIN vn.province p ON p.id = a.provinceFk
|
||||
JOIN vn.country c ON c.id = p.countryFk
|
||||
JOIN vn.ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN vn.state st ON st.id = ts.stateFk
|
||||
JOIN vn.alertLevel al ON al.id = ts.alertLevel
|
||||
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
|
||||
LEFT JOIN (
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
t.addressFk,
|
||||
t.id,
|
||||
t.shipped,
|
||||
st.name state,
|
||||
st.code,
|
||||
st.classColor,
|
||||
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
|
||||
FROM vn.ticket t
|
||||
JOIN vn.ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN vn.state st ON st.id = ts.stateFk
|
||||
JOIN vn.sale s ON s.ticketFk = t.id
|
||||
JOIN vn.item i ON i.id = s.itemFk
|
||||
WHERE t.shipped BETWEEN vFutureDated
|
||||
AND util.dayend(vFutureDated)
|
||||
AND t.warehouseFk = vWarehouseFk
|
||||
GROUP BY t.id
|
||||
) sub
|
||||
GROUP BY sub.addressFk
|
||||
) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id
|
||||
WHERE t.shipped BETWEEN vOriginDated AND util.dayend(vOriginDated)
|
||||
AND t.warehouseFk = vWarehouseFk
|
||||
AND al.code = 'FREE'
|
||||
AND tp.ticketFk IS NULL
|
||||
GROUP BY sv.ticketFk
|
||||
HAVING futureId;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `vn`.`ticket` MODIFY COLUMN warehouseFk smallint(6) unsigned DEFAULT NULL NULL;
|
|
@ -595,6 +595,8 @@ export default {
|
|||
moreMenuUpdateDiscount: 'vn-item[name="discount"]',
|
||||
moreMenuRecalculatePrice: 'vn-item[name="calculatePrice"]',
|
||||
moreMenuRefund: 'vn-item[name="refund"]',
|
||||
refundWithWarehouse: 'vn-item[name="refundWithWarehouse"]',
|
||||
refundWithoutWarehouse: 'vn-item[name="refundWithoutWarehouse"]',
|
||||
moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input',
|
||||
transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text',
|
||||
transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable',
|
||||
|
|
|
@ -220,14 +220,25 @@ describe('Ticket Edit sale path', () => {
|
|||
|
||||
it('should log in as salesAssistant and navigate to ticket sales', async() => {
|
||||
await page.loginAndModule('salesAssistant', 'ticket');
|
||||
await page.accessToSearchResult('16');
|
||||
await page.accessToSearchResult('17');
|
||||
await page.accessToSection('ticket.card.sale');
|
||||
});
|
||||
|
||||
it('should select the third sale and create a refund', async() => {
|
||||
it('should select the first sale and create a refund with warehouse', async() => {
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuRefund);
|
||||
await page.waitToClick(selectors.ticketSales.refundWithWarehouse);
|
||||
await page.waitForSnackbar();
|
||||
await page.waitForState('ticket.card.sale');
|
||||
});
|
||||
|
||||
it('should select the first sale and create a refund without warehouse', async() => {
|
||||
await page.accessToSearchResult('18');
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuRefund);
|
||||
await page.waitToClick(selectors.ticketSales.refundWithoutWarehouse);
|
||||
await page.waitForSnackbar();
|
||||
await page.waitForState('ticket.card.sale');
|
||||
});
|
||||
|
@ -246,7 +257,6 @@ describe('Ticket Edit sale path', () => {
|
|||
it('should select the third sale and create a claim of it', async() => {
|
||||
await page.accessToSearchResult('16');
|
||||
await page.accessToSection('ticket.card.sale');
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||
|
|
|
@ -49,7 +49,11 @@ describe('Claim summary path', () => {
|
|||
});
|
||||
|
||||
it(`should click on the first sale ID making the item descriptor visible`, async() => {
|
||||
await page.waitToClick(selectors.claimSummary.firstSaleItemId);
|
||||
const firstItem = selectors.claimSummary.firstSaleItemId;
|
||||
await page.evaluate(selectors => {
|
||||
document.querySelector(selectors).scrollIntoView();
|
||||
}, firstItem);
|
||||
await page.click(firstItem);
|
||||
await page.waitImgLoad(selectors.claimSummary.firstSaleDescriptorImage);
|
||||
const visible = await page.isVisible(selectors.claimSummary.itemDescriptorPopover);
|
||||
|
||||
|
|
|
@ -53,12 +53,10 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="model vn-pb-sm vn-px-sm"
|
||||
title="{{::log.changedModelValue}}"
|
||||
<div class="model vn-pb-sm vn-px-sm"
|
||||
ng-if="::log.changedModelId || log.changedModelValue">
|
||||
<span class="model-id" ng-if="::log.changedModelId">#{{::log.changedModelId}}</span>
|
||||
<span class="model-value">{{::log.changedModelValue}}</span>
|
||||
<span class="model-value" title="{{::log.changedModelValue}}">{{::log.changedModelValue}}</span>
|
||||
</div>
|
||||
<div class="changes vn-pa-sm"
|
||||
ng-class="{expanded: log.expand}"
|
||||
|
@ -75,16 +73,16 @@
|
|||
<span class="json-field" title="{{::prop.name}}">
|
||||
{{::prop.nameI18n}}:
|
||||
</span>
|
||||
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span>
|
||||
<vn-json-value value="::prop.val.val"></vn-json-value><span ng-if="::!$last">,</span>
|
||||
</span>
|
||||
<div ng-if="log.expand" class="expanded-json">
|
||||
<div ng-repeat="prop in ::log.props">
|
||||
<span class="json-field" title="{{::prop.name}}">
|
||||
{{::prop.nameI18n}}:
|
||||
</span>
|
||||
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
|
||||
<vn-log-value val="::prop.val"></vn-log-value>
|
||||
<span ng-if="::log.action == 'update'">
|
||||
← <vn-json-value value="::prop.old"></vn-json-value>
|
||||
← <vn-log-value val="::prop.old"></vn-log-value>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,12 +161,17 @@
|
|||
data="$ctrl.models"
|
||||
class="changed-model">
|
||||
</vn-autocomplete>
|
||||
<!-- FIXME: Cannot use LIKE with JSON columns
|
||||
<vn-textfield
|
||||
label="Changes"
|
||||
ng-model="filter.changes">
|
||||
<append>
|
||||
<vn-icon
|
||||
icon="info_outline"
|
||||
vn-tooltip="Search by changes"
|
||||
pointer>
|
||||
</vn-icon>
|
||||
</append>
|
||||
</vn-textfield>
|
||||
-->
|
||||
<vn-vertical>
|
||||
<vn-check
|
||||
label="Creates"
|
||||
|
|
|
@ -64,29 +64,47 @@ export default class Controller extends Section {
|
|||
set logs(value) {
|
||||
this._logs = value;
|
||||
if (!value) return;
|
||||
|
||||
const empty = {};
|
||||
const validations = window.validations;
|
||||
const castJsonValue = this.castJsonValue;
|
||||
|
||||
for (const log of value) {
|
||||
const oldValues = log.oldInstance || empty;
|
||||
const newValues = log.newInstance || empty;
|
||||
const notDelete = log.action != 'delete';
|
||||
const olds = (notDelete ? log.oldInstance : null) || empty;
|
||||
const vals = (notDelete ? log.newInstance : log.oldInstance) || empty;
|
||||
const locale = validations[log.changedModel]?.locale || empty;
|
||||
log.changedModelI18n = firstUpper(locale.name) || log.changedModel;
|
||||
|
||||
let props = Object.keys(oldValues).concat(Object.keys(newValues));
|
||||
let props = Object.keys(olds).concat(Object.keys(vals));
|
||||
props = [...new Set(props)];
|
||||
|
||||
log.props = [];
|
||||
for (const prop of props) {
|
||||
if (prop.endsWith('$')) continue;
|
||||
log.props.push({
|
||||
name: prop,
|
||||
nameI18n: firstUpper(locale.columns?.[prop]) || prop,
|
||||
old: this.castJsonValue(oldValues[prop]),
|
||||
new: this.castJsonValue(newValues[prop])
|
||||
old: getVal(olds, prop),
|
||||
val: getVal(vals, prop)
|
||||
});
|
||||
}
|
||||
log.props.sort(
|
||||
(a, b) => a.nameI18n.localeCompare(b.nameI18n));
|
||||
}
|
||||
|
||||
function getVal(vals, prop) {
|
||||
let val, id;
|
||||
const showProp = `${prop}$`;
|
||||
|
||||
if (vals[showProp] != null) {
|
||||
val = vals[showProp];
|
||||
id = vals[prop];
|
||||
} else
|
||||
val = vals[prop];
|
||||
|
||||
return {val: castJsonValue(val), id};
|
||||
}
|
||||
}
|
||||
|
||||
get models() {
|
||||
|
@ -113,10 +131,6 @@ export default class Controller extends Section {
|
|||
: value;
|
||||
}
|
||||
|
||||
mainVal(prop, action) {
|
||||
return action == 'delete' ? prop.old : prop.new;
|
||||
}
|
||||
|
||||
relativeDate(dateVal) {
|
||||
if (dateVal == null) return '';
|
||||
const date = new Date(dateVal);
|
||||
|
@ -150,14 +164,16 @@ export default class Controller extends Section {
|
|||
if (value == null || value == '') return null;
|
||||
switch (prop) {
|
||||
case 'search':
|
||||
if (/^[0-9]+$/.test(value))
|
||||
return {changedModelId: value};
|
||||
else
|
||||
return {changedModelValue: {like: `%${value}%`}};
|
||||
const or = [];
|
||||
if (/^[\w_-]+$/.test(value))
|
||||
or.push({changedModelId: value});
|
||||
if (!/^[0-9]+$/.test(value))
|
||||
or.push({changedModelValue: {like: `%${value}%`}});
|
||||
return or.length ? {or} : null;
|
||||
case 'changes':
|
||||
return {or: [
|
||||
{oldInstance: {like: `%${value}%`}},
|
||||
{newInstance: {like: `%${value}%`}},
|
||||
{oldJson: {like: `%${value}%`}},
|
||||
{newJson: {like: `%${value}%`}},
|
||||
{description: {like: `%${value}%`}}
|
||||
]};
|
||||
case 'who':
|
||||
|
@ -238,3 +254,12 @@ ngModule.vnComponent('vnLog', {
|
|||
url: '@'
|
||||
}
|
||||
});
|
||||
|
||||
ngModule.component('vnLogValue', {
|
||||
template:
|
||||
'<vn-json-value value="::$ctrl.val.val"></vn-json-value>' +
|
||||
'<span ng-if="::$ctrl.val.id" class="id-value"> #{{::$ctrl.val.id}}</span>',
|
||||
bindings: {
|
||||
val: '<?',
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,6 +2,9 @@ Date: Fecha
|
|||
Concept: Concepto
|
||||
Search: Buscar
|
||||
Search by id or concept: Buscar por identificador o concepto
|
||||
Search by changes: |
|
||||
Buscar por cambios realizados. Los atributos deben buscarse por su nombre
|
||||
interno, para obtenerlo situar el cursor sobre el nombre.
|
||||
Entity: Entidad
|
||||
Action: Acción
|
||||
Author: Autor
|
||||
|
|
|
@ -105,6 +105,7 @@ vn-log {
|
|||
& > .model-id {
|
||||
color: $color-font-secondary;
|
||||
font-size: .9rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,3 +145,7 @@ vn-log {
|
|||
}
|
||||
}
|
||||
}
|
||||
vn-log-value > .id-value {
|
||||
font-size: .9rem;
|
||||
color: $color-font-secondary;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,61 @@
|
|||
{
|
||||
"name": "Log",
|
||||
"base": "VnModel"
|
||||
"name": "Log",
|
||||
"base": "VnModel",
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"oldJson": {
|
||||
"type": "String",
|
||||
"mysql": {"columnName": "oldInstance"}
|
||||
},
|
||||
"newJson": {
|
||||
"type": "String",
|
||||
"mysql": {"columnName": "newInstance"}
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
name: subrole
|
||||
columns:
|
||||
id: id
|
||||
role: rol
|
||||
inheritsFrom: inherits
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
name: subrol
|
||||
columns:
|
||||
id: id
|
||||
role: rol
|
||||
inheritsFrom: hereda
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "account.roleLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "account.userLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "claimLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
name: SMS
|
||||
columns:
|
||||
id: id
|
||||
senderFk: sender
|
||||
sender: sender number
|
||||
destination: destination
|
||||
message: message
|
||||
statusCode: status code
|
||||
status: status
|
||||
created: created
|
|
@ -0,0 +1,10 @@
|
|||
name: SMS
|
||||
columns:
|
||||
id: id
|
||||
senderFk: remitente
|
||||
sender: número remitente
|
||||
destination: destinatario
|
||||
message: mensaje
|
||||
statusCode: código estado
|
||||
status: estado
|
||||
created: creado
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "clientLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "entryLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,57 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "invoiceInLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": [
|
||||
"creationDate DESC",
|
||||
"id DESC"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,19 @@ module.exports = Self => {
|
|||
Self.remoteMethod('refund', {
|
||||
description: 'Create refund tickets with sales and services if provided',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'ref',
|
||||
type: 'string',
|
||||
description: 'The invoice reference'
|
||||
}],
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ref',
|
||||
type: 'string',
|
||||
description: 'The invoice reference',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'withWarehouse',
|
||||
type: 'boolean',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['number'],
|
||||
root: true
|
||||
|
@ -17,7 +25,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.refund = async(ref, options) => {
|
||||
Self.refund = async(ref, withWarehouse, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
@ -35,7 +43,7 @@ module.exports = Self => {
|
|||
const tickets = await models.Ticket.find(filter, myOptions);
|
||||
|
||||
const ticketsIds = tickets.map(ticket => ticket.id);
|
||||
const refundedTickets = await models.Ticket.refund(ticketsIds, myOptions);
|
||||
const refundedTickets = await models.Ticket.refund(ticketsIds, withWarehouse, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ const LoopBackContext = require('loopback-context');
|
|||
|
||||
describe('InvoiceOut refund()', () => {
|
||||
const userId = 5;
|
||||
const withWarehouse = true;
|
||||
const activeCtx = {
|
||||
accessToken: {userId: userId},
|
||||
};
|
||||
|
@ -15,7 +16,7 @@ describe('InvoiceOut refund()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
try {
|
||||
const result = await models.InvoiceOut.refund('T1111111', options);
|
||||
const result = await models.InvoiceOut.refund('T1111111', withWarehouse, options);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
|
||||
|
|
|
@ -76,14 +76,27 @@
|
|||
translate>
|
||||
Show CITES letter
|
||||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="refundConfirmation.show()"
|
||||
name="refundInvoice"
|
||||
<vn-item class="dropdown"
|
||||
vn-click-stop="refundMenu.show($event, 'left')"
|
||||
vn-tooltip="Create a single ticket with all the content of the current invoice"
|
||||
vn-acl="invoicing, claimManager, salesAssistant"
|
||||
vn-acl-action="remove"
|
||||
translate>
|
||||
Refund
|
||||
Refund...
|
||||
<vn-menu vn-id="refundMenu">
|
||||
<vn-list>
|
||||
<vn-item
|
||||
ng-click="$ctrl.refundInvoiceOut(true)"
|
||||
translate>
|
||||
with warehouse
|
||||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="$ctrl.refundInvoiceOut(false)"
|
||||
translate>
|
||||
without warehouse
|
||||
</vn-item>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
</vn-item>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
|
@ -97,11 +110,6 @@
|
|||
on-accept="$ctrl.bookInvoiceOut()"
|
||||
question="Are you sure you want to book this invoice?">
|
||||
</vn-confirm>
|
||||
<vn-confirm
|
||||
vn-id="refundConfirmation"
|
||||
on-accept="$ctrl.refundInvoiceOut()"
|
||||
question="Are you sure you want to refund this invoice?">
|
||||
</vn-confirm>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
|
|
|
@ -114,9 +114,9 @@ class Controller extends Section {
|
|||
});
|
||||
}
|
||||
|
||||
refundInvoiceOut() {
|
||||
refundInvoiceOut(withWarehouse) {
|
||||
const query = 'InvoiceOuts/refund';
|
||||
const params = {ref: this.invoiceOut.ref};
|
||||
const params = {ref: this.invoiceOut.ref, withWarehouse: withWarehouse};
|
||||
this.$http.post(query, params).then(res => {
|
||||
const refundTicket = res.data;
|
||||
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
|
||||
|
|
|
@ -20,3 +20,4 @@ Regenerate PDF invoice: Regenerar PDF factura
|
|||
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
|
||||
The email can't be empty: El correo no puede estar vacío
|
||||
The following refund tickets have been created: "Se han creado los siguientes tickets de abono: {{ticketIds}}"
|
||||
Refund...: Abono...
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "itemLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class Controller extends SearchPanel {
|
|||
|
||||
addValue() {
|
||||
this.filter.values.push({});
|
||||
setTimeout(() => this.popover.relocate());
|
||||
setTimeout(() => this.parentPopover.relocate());
|
||||
}
|
||||
|
||||
changeTag() {
|
||||
|
@ -36,7 +36,7 @@ ngModule.vnComponent('vnOrderCatalogSearchPanel', {
|
|||
controller: Controller,
|
||||
bindings: {
|
||||
onSubmit: '&?',
|
||||
popover: '<?',
|
||||
parentPopover: '<?',
|
||||
resultTags: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
on-close="$ctrl.onPopoverClose()">
|
||||
<vn-order-catalog-search-panel
|
||||
on-submit="$ctrl.onPanelSubmit($filter)"
|
||||
popover="popover"
|
||||
parent-popover="popover"
|
||||
result-tags="$ctrl.resultTags">
|
||||
</vn-order-catalog-search-panel>
|
||||
</vn-popover>
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "routeLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,58 +1,9 @@
|
|||
{
|
||||
"name": "ShelvingLog",
|
||||
"name": "ShelvingLog",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "shelvingLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "shelvingLog"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "supplierLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ module.exports = Self => {
|
|||
{
|
||||
arg: 'servicesIds',
|
||||
type: ['number']
|
||||
},
|
||||
{
|
||||
arg: 'withWarehouse',
|
||||
type: 'boolean',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
|
@ -23,7 +28,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.refund = async(salesIds, servicesIds, options) => {
|
||||
Self.refund = async(salesIds, servicesIds, withWarehouse, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
@ -65,7 +70,7 @@ module.exports = Self => {
|
|||
const now = Date.vnNew();
|
||||
const [firstTicketId] = ticketsIds;
|
||||
|
||||
const refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, myOptions);
|
||||
const refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions);
|
||||
|
||||
for (const sale of sales) {
|
||||
const createdSale = await models.Sale.create({
|
||||
|
@ -113,7 +118,7 @@ module.exports = Self => {
|
|||
}
|
||||
};
|
||||
|
||||
async function createTicketRefund(ticketId, now, refundAgencyMode, refoundZoneId, myOptions) {
|
||||
async function createTicketRefund(ticketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions) {
|
||||
const models = Self.app.models;
|
||||
|
||||
const filter = {include: {relation: 'address'}};
|
||||
|
@ -125,7 +130,7 @@ module.exports = Self => {
|
|||
addressFk: ticket.address().id,
|
||||
agencyModeFk: refundAgencyMode.id,
|
||||
nickname: ticket.address().nickname,
|
||||
warehouseFk: ticket.warehouseFk,
|
||||
warehouseFk: withWarehouse ? ticket.warehouseFk : null,
|
||||
companyFk: ticket.companyFk,
|
||||
landed: now,
|
||||
zoneFk: refoundZoneId
|
||||
|
|
|
@ -6,8 +6,8 @@ describe('Sale refund()', () => {
|
|||
const activeCtx = {
|
||||
accessToken: {userId: userId},
|
||||
};
|
||||
|
||||
const servicesIds = [3];
|
||||
const withWarehouse = true;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
|
@ -22,7 +22,7 @@ describe('Sale refund()', () => {
|
|||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const refundedTicket = await models.Sale.refund(salesIds, servicesIds, options);
|
||||
const refundedTicket = await models.Sale.refund(salesIds, servicesIds, withWarehouse, options);
|
||||
|
||||
expect(refundedTicket).toBeDefined();
|
||||
|
||||
|
@ -40,7 +40,7 @@ describe('Sale refund()', () => {
|
|||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ticket = await models.Sale.refund(salesIds, servicesIds, options);
|
||||
const ticket = await models.Sale.refund(salesIds, servicesIds, withWarehouse, options);
|
||||
|
||||
const refundedTicket = await models.Ticket.findOne({
|
||||
where: {
|
||||
|
|
|
@ -7,6 +7,11 @@ module.exports = Self => {
|
|||
arg: 'ticketsIds',
|
||||
type: ['number'],
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'withWarehouse',
|
||||
type: 'boolean',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
|
@ -19,7 +24,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.refund = async(ticketsIds, options) => {
|
||||
Self.refund = async(ticketsIds, withWarehouse, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
@ -41,7 +46,7 @@ module.exports = Self => {
|
|||
const services = await models.TicketService.find(filter, myOptions);
|
||||
const servicesIds = services.map(service => service.id);
|
||||
|
||||
const refundedTickets = await models.Sale.refund(salesIds, servicesIds, myOptions);
|
||||
const refundedTickets = await models.Sale.refund(salesIds, servicesIds, withWarehouse, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
|
|
|
@ -1,58 +1,9 @@
|
|||
{
|
||||
"name": "TicketLog",
|
||||
"name": "TicketLog",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "ticketLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "ticketLog"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
<td>{{::ticket.futureIpt | dashIfEmpty}}</td>
|
||||
<td>
|
||||
<span
|
||||
class="chip {{ticket.classColor}}">
|
||||
class="chip {{ticket.futureClassColor}}">
|
||||
{{::ticket.futureState | dashIfEmpty}}
|
||||
</span>
|
||||
</td>
|
||||
|
|
|
@ -102,13 +102,6 @@ export default class Controller extends Section {
|
|||
return checkedLines;
|
||||
}
|
||||
|
||||
stateColor(state) {
|
||||
if (state === 'OK')
|
||||
return 'success';
|
||||
else if (state === 'Libre')
|
||||
return 'notice';
|
||||
}
|
||||
|
||||
dateRange(value) {
|
||||
const minHour = new Date(value);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
|
|
|
@ -61,24 +61,6 @@ describe('Component vnTicketAdvance', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('stateColor()', () => {
|
||||
it('should return success to the OK tickets', () => {
|
||||
const ok = controller.stateColor(controller.$.model.data[0].state);
|
||||
const notOk = controller.stateColor(controller.$.model.data[1].state);
|
||||
|
||||
expect(ok).toEqual('success');
|
||||
expect(notOk).not.toEqual('success');
|
||||
});
|
||||
|
||||
it('should return success to the FREE tickets', () => {
|
||||
const notFree = controller.stateColor(controller.$.model.data[0].state);
|
||||
const free = controller.stateColor(controller.$.model.data[1].state);
|
||||
|
||||
expect(free).toEqual('notice');
|
||||
expect(notFree).not.toEqual('notice');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dateRange()', () => {
|
||||
it('should return two dates with the hours at the start and end of the given date', () => {
|
||||
const now = Date.vnNew();
|
||||
|
|
|
@ -141,12 +141,27 @@
|
|||
translate>
|
||||
Recalculate components
|
||||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="refundAllConfirmation.show()"
|
||||
<vn-item class="dropdown"
|
||||
vn-click-stop="refundMenu.show($event, 'left')"
|
||||
vn-acl="invoicing, claimManager, salesAssistant"
|
||||
vn-acl-action="remove"
|
||||
vn-tooltip="Create a single ticket with all the content of the current ticket"
|
||||
translate>
|
||||
Refund all
|
||||
Refund all...
|
||||
<vn-menu vn-id="refundMenu">
|
||||
<vn-list>
|
||||
<vn-item
|
||||
ng-click="$ctrl.refund(true)"
|
||||
translate>
|
||||
with warehouse
|
||||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="$ctrl.refund(false)"
|
||||
translate>
|
||||
without warehouse
|
||||
</vn-item>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
</vn-item>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
|
@ -319,14 +334,6 @@
|
|||
message="Recalculate components">
|
||||
</vn-confirm>
|
||||
|
||||
<!-- Refund all confirmation dialog -->
|
||||
<vn-confirm
|
||||
vn-id="refundAllConfirmation"
|
||||
on-accept="$ctrl.refund()"
|
||||
question="Are you sure you want to refund all?"
|
||||
message="Refund all">
|
||||
</vn-confirm>
|
||||
|
||||
<!-- Client balance popup-->
|
||||
<vn-client-balance-create
|
||||
vn-id="balance-create"
|
||||
|
|
|
@ -297,16 +297,17 @@ class Controller extends Section {
|
|||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
||||
}
|
||||
|
||||
async refund() {
|
||||
const params = {ticketsIds: [this.id]};
|
||||
refund(withWarehouse) {
|
||||
const params = {ticketsIds: [this.id], withWarehouse: withWarehouse};
|
||||
const query = 'Tickets/refund';
|
||||
return this.$http.post(query, params).then(res => {
|
||||
const refundTicket = res.data;
|
||||
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
|
||||
ticketId: refundTicket.id
|
||||
}));
|
||||
this.$state.go('ticket.card.sale', {id: refundTicket.id});
|
||||
});
|
||||
return this.$http.post(query, params)
|
||||
.then(res => {
|
||||
const refundTicket = res.data;
|
||||
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
|
||||
ticketId: refundTicket.id
|
||||
}));
|
||||
this.$state.go('ticket.card.sale', {id: refundTicket.id});
|
||||
});
|
||||
}
|
||||
|
||||
onSmsSend(sms) {
|
||||
|
|
|
@ -10,7 +10,9 @@ Send CSV: Enviar CSV
|
|||
Send CSV Delivery Note: Enviar albarán en CSV
|
||||
Send PDF Delivery Note: Enviar albarán en PDF
|
||||
Show Proforma: Ver proforma
|
||||
Refund all: Abonar todo
|
||||
Refund all...: Abonar todo...
|
||||
with warehouse: con almacén
|
||||
without warehouse: sin almacén
|
||||
Invoice sent: Factura enviada
|
||||
The following refund ticket have been created: "Se ha creado siguiente ticket de abono: {{ticketId}}"
|
||||
Transfer client: Transferir cliente
|
||||
|
@ -18,3 +20,4 @@ SMS Notify changes: SMS Notificar cambios
|
|||
PDF sent!: ¡PDF enviado!
|
||||
Already exist signed delivery note: Ya existe albarán de entrega firmado
|
||||
Are you sure you want to replace this delivery note?: ¿Seguro que quieres reemplazar este albarán de entrega?
|
||||
Create a single ticket with all the content of the current ticket: Crea un ticket único con todo el contenido del ticket actual
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
<td>{{::ticket.futureIpt | dashIfEmpty}}</td>
|
||||
<td>
|
||||
<span
|
||||
class="chip {{ticket.classColor}}">
|
||||
class="chip {{ticket.futureClassColor}}">
|
||||
{{::ticket.futureState}}
|
||||
</span>
|
||||
</td>
|
||||
|
|
|
@ -529,11 +529,28 @@
|
|||
ng-if="$ctrl.isEditable && $ctrl.hasReserves()">
|
||||
Unmark as reserved
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
name="refund"
|
||||
ng-click="$ctrl.createRefund()"
|
||||
vn-acl="invoicing, claimManager, salesAssistant"
|
||||
vn-acl-action="remove">
|
||||
Refund
|
||||
</vn-item>
|
||||
<vn-item class="dropdown"
|
||||
name="refund"
|
||||
vn-click-stop="refundMenu.show($event, 'left')"
|
||||
vn-acl="invoicing, claimManager, salesAssistant"
|
||||
vn-acl-action="remove"
|
||||
translate>
|
||||
Refund...
|
||||
<vn-menu vn-id="refundMenu">
|
||||
<vn-list>
|
||||
<vn-item
|
||||
name="refundWithWarehouse"
|
||||
ng-click="$ctrl.createRefund(true)"
|
||||
translate>
|
||||
with warehouse
|
||||
</vn-item>
|
||||
<vn-item
|
||||
name="refundWithoutWarehouse"
|
||||
ng-click="$ctrl.createRefund(false)"
|
||||
translate>
|
||||
without warehouse
|
||||
</vn-item>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
</vn-item>
|
||||
</vn-menu>
|
||||
|
|
|
@ -520,13 +520,12 @@ class Controller extends Section {
|
|||
});
|
||||
}
|
||||
|
||||
createRefund() {
|
||||
createRefund(withWarehouse) {
|
||||
const sales = this.selectedValidSales();
|
||||
if (!sales) return;
|
||||
|
||||
const salesIds = sales.map(sale => sale.id);
|
||||
|
||||
const params = {salesIds: salesIds};
|
||||
const params = {salesIds: salesIds, withWarehouse: withWarehouse};
|
||||
const query = 'Sales/refund';
|
||||
this.$http.post(query, params).then(res => {
|
||||
const refundTicket = res.data;
|
||||
|
|
|
@ -36,7 +36,7 @@ Warehouse: Almacen
|
|||
Agency: Agencia
|
||||
Shipped: F. envio
|
||||
Packaging: Encajado
|
||||
Refund: Abono
|
||||
Refund...: Abono...
|
||||
Promotion mana: Maná promoción
|
||||
Claim mana: Maná reclamación
|
||||
History: Historial
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "travelLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,14 @@
|
|||
{
|
||||
"name": "DeviceProductionLog",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "deviceProductionLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"deviceProduction": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
"name": "DeviceProductionLog",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "deviceProductionLog"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["created DESC", "id DESC"]
|
||||
"properties": {
|
||||
"deviceProduction": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "workerLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,5 @@
|
|||
"mysql": {
|
||||
"table": "zoneLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "23.22.01",
|
||||
"version": "23.24.01",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "salix-back",
|
||||
"version": "23.22.01",
|
||||
"version": "23.24.01",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.2.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-back",
|
||||
"version": "23.24.01",
|
||||
"version": "23.26.01",
|
||||
"author": "Verdnatura Levante SL",
|
||||
"description": "Salix backend",
|
||||
"license": "GPL-3.0",
|
||||
|
|
|
@ -9,7 +9,7 @@ let mode = env == 'development' ? env : 'production';
|
|||
|
||||
let baseConfig = {
|
||||
entry: {salix: 'salix'},
|
||||
mode: mode,
|
||||
mode,
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
publicPath: '/'
|
||||
|
|
Loading…
Reference in New Issue