refactor(claim): removed importTicketSales and fix tests
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
parent
52cf79516a
commit
fc3a46eb26
|
@ -0,0 +1,2 @@
|
|||
DELETE FROM salix.ACL
|
||||
WHERE model = 'ClaimEnd' AND property = 'importTicketSales';
|
|
@ -1706,7 +1706,7 @@ INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `
|
|||
(1, CURDATE(), 1, 'Cu nam labores lobortis definiebas, ei aliquyam salutatus persequeris quo, cum eu nemore fierent dissentiunt. Per vero dolor id, vide democritum scribentur eu vim, pri erroribus temporibus ex.', 1101, 18, 3, 0, CURDATE()),
|
||||
(2, CURDATE(), 2, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.', 1101, 18, 3, 0, CURDATE()),
|
||||
(3, CURDATE(), 3, 'An vim commodo dolorem volutpat, cu expetendis voluptatum usu, et mutat consul adversarium his. His natum numquam legimus an, diam fabulas mei ut. Melius fabellas sadipscing vel id. Partem diceret mandamus mea ne, has te tempor nostrud. Aeque nostro eum no.', 1101, 18, 1, 1, CURDATE()),
|
||||
(4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque,', 1104, 18, 5, 0, CURDATE());
|
||||
(4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque.', 1104, 18, 5, 0, CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`)
|
||||
VALUES
|
||||
|
|
|
@ -680,13 +680,13 @@ export default {
|
|||
header: 'vn-claim-summary > vn-card > h5',
|
||||
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
||||
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"]',
|
||||
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
||||
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
||||
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
||||
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
||||
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
|
||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
||||
},
|
||||
claimBasicData: {
|
||||
|
@ -722,10 +722,7 @@ export default {
|
|||
},
|
||||
claimAction: {
|
||||
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
|
||||
importTicketButton: 'vn-claim-action vn-button[label="Import ticket"]',
|
||||
secondImportableTicket: '.vn-popover.shown .content > div > vn-table > div > vn-tbody > vn-tr:nth-child(2)',
|
||||
firstLineDestination: 'vn-claim-action vn-tr:nth-child(1) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
|
||||
secondLineDestination: 'vn-claim-action vn-tr:nth-child(2) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
|
||||
anyLine: 'vn-claim-action vn-tbody > vn-tr',
|
||||
firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
||||
},
|
||||
|
|
|
@ -24,22 +24,6 @@ describe('Claim action path', () => {
|
|||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should import the second importable ticket', async() => {
|
||||
await page.waitToClick(selectors.claimAction.importTicketButton);
|
||||
await page.waitToClick(selectors.claimAction.secondImportableTicket);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should edit the second line destination field', async() => {
|
||||
await page.waitForContentLoaded();
|
||||
await page.autocompleteSearch(selectors.claimAction.secondLineDestination, 'Bueno');
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should delete the first line', async() => {
|
||||
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
@ -47,18 +31,11 @@ describe('Claim action path', () => {
|
|||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should refresh the view to check the remaining line is the expected one', async() => {
|
||||
it('should refresh the view to check not have lines', async() => {
|
||||
await page.reloadSection('claim.card.action');
|
||||
const result = await page.waitToGetProperty(selectors.claimAction.firstLineDestination, 'value');
|
||||
const result = await page.countElement(selectors.claimAction.anyLine);
|
||||
|
||||
expect(result).toEqual('Bueno');
|
||||
});
|
||||
|
||||
it('should delete the current first line', async() => {
|
||||
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
expect(result).toEqual(0);
|
||||
});
|
||||
|
||||
it('should check the "is paid with mana" checkbox', async() => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
|
@ -38,7 +39,7 @@ describe('Claim summary path', () => {
|
|||
it('should display the observation', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'value');
|
||||
|
||||
expect(result).toContain('observation four');
|
||||
expect(result).toContain('Wisi forensibus mnesarchum in cum. Per id impetus abhorreant');
|
||||
});
|
||||
|
||||
it('should display the claimed line(s)', async() => {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('importTicketSales', {
|
||||
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'params',
|
||||
type: 'object',
|
||||
http: {source: 'body'}
|
||||
}],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/importTicketSales`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.importTicketSales = async(ctx, params, options) => {
|
||||
let models = Self.app.models;
|
||||
let userId = ctx.req.accessToken.userId;
|
||||
|
||||
let tx;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions);
|
||||
|
||||
let ticketSales = await models.Sale.find({
|
||||
where: {ticketFk: params.ticketFk}
|
||||
}, myOptions);
|
||||
|
||||
let claimEnds = [];
|
||||
ticketSales.forEach(sale => {
|
||||
claimEnds.push({
|
||||
saleFk: sale.id,
|
||||
claimFk: params.claimFk,
|
||||
workerFk: worker.id
|
||||
});
|
||||
});
|
||||
|
||||
const createdClaimEnds = await Self.create(claimEnds, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return createdClaimEnds;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('Claim importTicketSales()', () => {
|
||||
it('should import sales to a claim actions from an specific ticket', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 5}}};
|
||||
|
||||
const tx = await app.models.Entry.beginTransaction({});
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
||||
claimFk: 1,
|
||||
ticketFk: 1
|
||||
}, options);
|
||||
|
||||
expect(claimEnds.length).toEqual(4);
|
||||
expect(claimEnds[0].saleFk).toEqual(1);
|
||||
expect(claimEnds[2].saleFk).toEqual(3);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('regularizeClaim', {
|
||||
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
|
||||
description: `Imports lines from claimBeginning to a new ticket
|
||||
with specific shipped, landed dates, agency and company`,
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('claim regularizeClaim()', () => {
|
||||
const userId = 18;
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 18},
|
||||
accessToken: {userId: userId},
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
};
|
||||
|
@ -11,8 +12,9 @@ describe('claim regularizeClaim()', () => {
|
|||
return params.nickname;
|
||||
};
|
||||
|
||||
const chatModel = app.models.Chat;
|
||||
const claimFk = 1;
|
||||
const chatModel = models.Chat;
|
||||
const claimId = 1;
|
||||
const ticketId = 1;
|
||||
const pendentState = 1;
|
||||
const resolvedState = 3;
|
||||
const trashDestination = 2;
|
||||
|
@ -21,27 +23,40 @@ describe('claim regularizeClaim()', () => {
|
|||
let claimEnds = [];
|
||||
let trashTicket;
|
||||
|
||||
async function importTicket(ticketId, claimId, userId, options) {
|
||||
const ticketSales = await models.Sale.find({
|
||||
where: {ticketFk: ticketId}
|
||||
}, options);
|
||||
const claimEnds = [];
|
||||
for (let sale of ticketSales) {
|
||||
claimEnds.push({
|
||||
saleFk: sale.id,
|
||||
claimFk: claimId,
|
||||
workerFk: userId
|
||||
});
|
||||
}
|
||||
|
||||
return await models.ClaimEnd.create(claimEnds, options);
|
||||
}
|
||||
|
||||
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
|
||||
const tx = await app.models.Claim.beginTransaction({});
|
||||
const tx = await models.Claim.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||
|
||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
||||
claimFk: claimFk,
|
||||
ticketFk: 1
|
||||
}, options);
|
||||
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||
|
||||
for (claimEnd of claimEnds)
|
||||
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
|
||||
|
||||
let claimBefore = await app.models.Claim.findById(claimFk, null, options);
|
||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
||||
let claimAfter = await app.models.Claim.findById(claimFk, null, options);
|
||||
let claimBefore = await models.Claim.findById(claimId, null, options);
|
||||
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||
let claimAfter = await models.Claim.findById(claimId, null, options);
|
||||
|
||||
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options);
|
||||
trashTicket = await models.Ticket.findOne({where: {addressFk: 12}}, options);
|
||||
|
||||
expect(trashTicket.addressFk).toEqual(trashAddress);
|
||||
expect(claimBefore.claimStateFk).toEqual(pendentState);
|
||||
|
@ -57,22 +72,19 @@ describe('claim regularizeClaim()', () => {
|
|||
});
|
||||
|
||||
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
|
||||
const tx = await app.models.Claim.beginTransaction({});
|
||||
const tx = await models.Claim.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||
|
||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
||||
claimFk: claimFk,
|
||||
ticketFk: 1
|
||||
}, options);
|
||||
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||
|
||||
for (claimEnd of claimEnds)
|
||||
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
||||
|
||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
||||
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||
|
||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
||||
|
@ -85,22 +97,19 @@ describe('claim regularizeClaim()', () => {
|
|||
});
|
||||
|
||||
it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => {
|
||||
const tx = await app.models.Claim.beginTransaction({});
|
||||
const tx = await models.Claim.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||
|
||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
||||
claimFk: claimFk,
|
||||
ticketFk: 1
|
||||
}, options);
|
||||
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||
|
||||
for (claimEnd of claimEnds)
|
||||
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
||||
|
||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
||||
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||
|
||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/claim-end/importTicketSales')(Self);
|
||||
};
|
|
@ -24,15 +24,9 @@
|
|||
<vn-button
|
||||
label="Import claim"
|
||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
||||
vn-http-click="$ctrl.importToNewRefundTicket()"p
|
||||
vn-http-click="$ctrl.importToNewRefundTicket()"
|
||||
translate-attr="{title: 'Imports claim details'}">
|
||||
</vn-button>
|
||||
<vn-button
|
||||
label="Import ticket"
|
||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
||||
ng-click="$ctrl.showLastTickets($event)"
|
||||
translate-attr="{title: 'Imports ticket lines'}">
|
||||
</vn-button>
|
||||
<vn-range
|
||||
label="Responsability"
|
||||
min-label="Company"
|
||||
|
@ -121,38 +115,6 @@
|
|||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</vn-card>
|
||||
<vn-crud-model
|
||||
vn-id="lastTicketsModel"
|
||||
url="Tickets"
|
||||
limit="20"
|
||||
data="lastTickets" auto-load="false">
|
||||
</vn-crud-model>
|
||||
<!-- Transfer Popover -->
|
||||
<vn-popover class="lastTicketsPopover" vn-id="lastTicketsPopover">
|
||||
<div class="ticketList vn-pa-md">
|
||||
<vn-table model="lastTicketsModel" auto-load="false">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>ID</vn-th>
|
||||
<vn-th field="shipped" default-order="DESC">F. envio</vn-th>
|
||||
<vn-th>Agencia</vn-th>
|
||||
<vn-th>Almacen</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr
|
||||
class="clickable"
|
||||
ng-repeat="ticket in lastTickets"
|
||||
ng-click="$ctrl.importTicketLines(ticket.id)">
|
||||
<vn-td number>{{::ticket.id}}</vn-td>
|
||||
<vn-td>{{::ticket.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td>{{::ticket.agencyMode.name}}</vn-td>
|
||||
<vn-td>{{::ticket.warehouse.name}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</div>
|
||||
</vn-popover>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="item-descriptor"
|
||||
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
||||
|
|
|
@ -60,36 +60,6 @@ export default class Controller extends Section {
|
|||
});
|
||||
}
|
||||
|
||||
showLastTickets(event) {
|
||||
let pastWeek = new Date();
|
||||
pastWeek.setDate(-7);
|
||||
|
||||
let filter = {
|
||||
include: [
|
||||
{relation: 'agencyMode', fields: ['name']},
|
||||
{relation: 'warehouse', fields: ['name']}
|
||||
],
|
||||
where: {
|
||||
created: {gt: pastWeek},
|
||||
clientFk: this.claim.clientFk
|
||||
}
|
||||
};
|
||||
this.$.lastTicketsModel.filter = filter;
|
||||
this.$.lastTicketsModel.refresh();
|
||||
this.$.lastTicketsPopover.show(event);
|
||||
}
|
||||
|
||||
importTicketLines(ticketFk) {
|
||||
let data = {claimFk: this.$params.id, ticketFk: ticketFk};
|
||||
|
||||
let query = `ClaimEnds/importTicketSales`;
|
||||
this.$http.post(query, data).then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
this.$.lastTicketsPopover.hide();
|
||||
this.$.model.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
regularize() {
|
||||
const query = `Claims/${this.$params.id}/regularizeClaim`;
|
||||
return this.$http.post(query).then(() => {
|
||||
|
|
|
@ -67,35 +67,6 @@ describe('claim', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('showLastTickets()', () => {
|
||||
it('should get a list of tickets and call lastTicketsPopover show() method', () => {
|
||||
jest.spyOn(controller.$.lastTicketsModel, 'refresh');
|
||||
jest.spyOn(controller.$.lastTicketsPopover, 'show');
|
||||
|
||||
controller.showLastTickets({});
|
||||
|
||||
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalled();
|
||||
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('importTicketLines()', () => {
|
||||
it('should perform a post query and add lines from an existent ticket', () => {
|
||||
jest.spyOn(controller.$.model, 'refresh');
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
jest.spyOn(controller.$.lastTicketsPopover, 'hide');
|
||||
|
||||
let data = {claimFk: 1, ticketFk: 1};
|
||||
$httpBackend.expect('POST', `ClaimEnds/importTicketSales`, data).respond({});
|
||||
controller.importTicketLines(1);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
expect(controller.$.lastTicketsPopover.hide).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('regularize()', () => {
|
||||
it('should perform a post query and reload the claim card', () => {
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
|
|
|
@ -3,8 +3,6 @@ Action: Actuaciones
|
|||
Total claimed: Total Reclamado
|
||||
Import claim: Importar reclamacion
|
||||
Imports claim details: Importa detalles de la reclamacion
|
||||
Import ticket: Importar ticket
|
||||
Imports ticket lines: Importa las lineas de un ticket
|
||||
Regularize: Regularizar
|
||||
Do you want to insert greuges?: Desea insertar greuges?
|
||||
Insert greuges on client card: Insertar greuges en la ficha del cliente
|
||||
|
|
Loading…
Reference in New Issue