Tests passed
This commit is contained in:
parent
a9d5e87078
commit
a72c12e1c9
|
@ -219,7 +219,7 @@ export default {
|
|||
goBackToModuleIndexButton: 'vn-item-descriptor a[href="#!/item/index"]',
|
||||
moreMenu: 'vn-item-descriptor vn-icon-menu > div > vn-icon',
|
||||
moreMenuRegularizeButton: '.vn-popover.shown .vn-drop-down li[name="Regularize stock"]',
|
||||
regularizeQuantityInput: 'vn-item-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-textfield > div > div > div.infix > input',
|
||||
regularizeQuantityInput: 'vn-item-descriptor vn-dialog tpl-body > div > vn-textfield input',
|
||||
regularizeWarehouseAutocomplete: 'vn-item-descriptor vn-dialog vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
|
||||
editButton: 'vn-item-card vn-item-descriptor vn-float-button[icon="edit"]',
|
||||
regularizeSaveButton: 'vn-item-descriptor > vn-dialog > div > form > div.buttons > tpl-buttons > button',
|
||||
|
@ -232,7 +232,7 @@ export default {
|
|||
typeAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.typeFk"]',
|
||||
intrastatAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.intrastatFk"]',
|
||||
nameInput: 'vn-textfield[label="Name"] input',
|
||||
relevancyInput: 'vn-input-number[ng-model="Relevancy"] input',
|
||||
relevancyInput: 'vn-input-number[ng-model="$ctrl.item.relevancy"] input',
|
||||
originAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]',
|
||||
expenceAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.expenceFk"]',
|
||||
longNameInput: 'vn-textfield[ng-model="$ctrl.item.longName"] input',
|
||||
|
@ -324,7 +324,7 @@ export default {
|
|||
setOk: 'vn-ticket-summary vn-button[label="SET OK"] > button'
|
||||
},
|
||||
ticketsIndex: {
|
||||
openAdvancedSearchButton: 'vn-ticket-index vn-searchbar .append > vn-icon[icon="keyboard_arrow_down"]',
|
||||
openAdvancedSearchButton: 'vn-ticket-index vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"] input',
|
||||
newTicketButton: 'vn-ticket-index > a',
|
||||
searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
|
||||
|
@ -332,7 +332,7 @@ export default {
|
|||
searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)',
|
||||
searchTicketInput: `vn-ticket-index ${components.vnTextfield}`,
|
||||
searchWeeklyTicketInput: `vn-ticket-weekly-index ${components.vnTextfield}`,
|
||||
searchWeeklyClearInput: 'vn-ticket-weekly-index vn-searchbar i[class="material-icons clear"]',
|
||||
searchWeeklyClearInput: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon=clear]',
|
||||
advancedSearchButton: 'vn-ticket-search-panel vn-submit[label="Search"] input',
|
||||
searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]',
|
||||
searchWeeklyButton: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon="search"]',
|
||||
|
@ -390,7 +390,7 @@ export default {
|
|||
ticketPackages: {
|
||||
packagesButton: 'vn-left-menu a[ui-sref="ticket.card.package"]',
|
||||
firstPackageAutocomplete: 'vn-autocomplete[label="Package"]',
|
||||
firstQuantityInput: 'vn-input-number[ng-model="Quantity"] input',
|
||||
firstQuantityInput: 'vn-input-number[ng-model="package.quantity"] input',
|
||||
firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]',
|
||||
addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]',
|
||||
clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] .icons > vn-icon[icon=clear]',
|
||||
|
@ -477,20 +477,18 @@ export default {
|
|||
chargesReasonAutocomplete: 'vn-autocomplete[ng-model="$ctrl.ticket.option"]',
|
||||
},
|
||||
ticketComponents: {
|
||||
base: 'vn-ticket-components tfoot > tr:nth-child(1) > td',
|
||||
margin: 'vn-ticket-components tfoot > tr:nth-child(2) > td',
|
||||
total: 'vn-ticket-components tfoot > tr:nth-child(3) > td'
|
||||
base: 'vn-ticket-components [name="base-sum"]'
|
||||
},
|
||||
ticketRequests: {
|
||||
addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button',
|
||||
request: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr',
|
||||
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield > div > div > div.infix > input',
|
||||
request: 'vn-ticket-request-index vn-table vn-tr',
|
||||
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield input',
|
||||
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.atenderFk"]',
|
||||
quantityInput: 'vn-ticket-request-create vn-input-number input[name=quantity]',
|
||||
priceInput: 'vn-ticket-request-create vn-input-number input[name=price]',
|
||||
firstRemoveRequestButton: 'vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)',
|
||||
saveButton: 'vn-ticket-request-create > form > div > vn-button-bar > vn-submit[label="Create"] input',
|
||||
firstDescription: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2)',
|
||||
firstDescription: 'vn-ticket-request-index vn-table vn-tr:nth-child(1) > vn-td:nth-child(2)',
|
||||
|
||||
},
|
||||
ticketLog: {
|
||||
|
@ -506,7 +504,7 @@ export default {
|
|||
firstQuantityInput: 'vn-ticket-service vn-input-number[label="Quantity"] input',
|
||||
firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input',
|
||||
firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]',
|
||||
fistDeleteServiceButton: 'vn-ticket-card > vn-main-block > div.content-block.ng-scope > vn-ticket-service > form > vn-card > div > vn-one:nth-child(1) > vn-horizontal:nth-child(1) > vn-auto > vn-icon-button[icon="delete"]',
|
||||
fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
newDescriptionInput: 'vn-ticket-service > vn-dialog vn-textfield[ng-model="$ctrl.newServiceType.name"] input',
|
||||
serviceLine: 'vn-ticket-service > form > vn-card > div > vn-one:nth-child(2) > vn-horizontal',
|
||||
saveServiceButton: `${components.vnSubmit}`,
|
||||
|
@ -531,7 +529,7 @@ export default {
|
|||
claimSummary: {
|
||||
header: 'vn-claim-summary > vn-card > div > h5',
|
||||
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
||||
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"] > div > textarea',
|
||||
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"] textarea',
|
||||
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',
|
||||
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
||||
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
||||
|
@ -549,7 +547,7 @@ export default {
|
|||
},
|
||||
claimDetail: {
|
||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
|
||||
discountInput: '.vn-popover.shown vn-input-number[ng-model="$ctrl.newDiscount"] > div > div > div.infix > input',
|
||||
discountInput: '.vn-popover.shown vn-input-number[ng-model="$ctrl.newDiscount"] input',
|
||||
discoutPopoverMana: '.vn-popover.shown .content > div > vn-horizontal > h5',
|
||||
addItemButton: 'vn-claim-detail a vn-float-button',
|
||||
firstClaimableSaleFromTicket: 'vn-claim-detail > vn-dialog vn-tbody > vn-tr',
|
||||
|
@ -608,7 +606,7 @@ export default {
|
|||
typeAutocomplete: 'vn-autocomplete[data="$ctrl.itemTypes"]',
|
||||
itemIdInput: 'vn-catalog-filter vn-textfield[ng-model="$ctrl.itemFk"] input',
|
||||
itemTagValueInput: 'vn-catalog-filter vn-textfield[ng-model="$ctrl.value"] input',
|
||||
openTagSearch: 'vn-catalog-filter > div > vn-vertical > vn-textfield[ng-model="$ctrl.value"] .append > i',
|
||||
openTagSearch: 'vn-catalog-filter > div > vn-vertical > vn-textfield[ng-model="$ctrl.value"] .append i',
|
||||
tagAutocomplete: 'vn-order-catalog-search-panel vn-autocomplete[ng-model="filter.tagFk"]',
|
||||
tagValueInput: 'vn-order-catalog-search-panel vn-textfield[ng-model="filter.value"] input',
|
||||
searchTagButton: 'vn-order-catalog-search-panel > div > form > vn-horizontal:nth-child(3) > vn-submit > input',
|
||||
|
|
|
@ -176,7 +176,7 @@ describe('Client lock verified data path', () => {
|
|||
.wait(selectors.clientFiscalData.socialNameInput)
|
||||
.evaluate(selector => {
|
||||
return document.querySelector(selector).disabled;
|
||||
}, 'vn-textfield[model="$ctrl.client.socialName"] > div');
|
||||
}, 'vn-textfield[ng-model="$ctrl.client.socialName"] > div');
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
|
|
@ -160,7 +160,7 @@ describe('Ticket descriptor path', () => {
|
|||
|
||||
it('should confirm the sixth weekly ticket was deleted', async() => {
|
||||
const result = await nightmare
|
||||
.waitToClick('vn-ticket-weekly-index vn-searchbar i[class="material-icons clear"]')
|
||||
.waitToClick('vn-ticket-weekly-index vn-searchbar vn-icon[icon=clear]')
|
||||
.waitToClick(selectors.ticketsIndex.searchWeeklyButton)
|
||||
.waitForNumberOfElements(selectors.ticketsIndex.searchWeeklyResult, 5)
|
||||
.countElement(selectors.ticketsIndex.searchWeeklyResult);
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('Ticket services path', () => {
|
|||
.waitToClick(selectors.ticketService.saveDescriptionButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
expect(result).toEqual(`Name can't be empty`);
|
||||
expect(result).toEqual(`can't be blank`);
|
||||
});
|
||||
|
||||
it('should create a new description then add price then create the service', async() => {
|
||||
|
|
|
@ -49,7 +49,7 @@ xdescribe('Route basic Data path', () => {
|
|||
|
||||
it('should count how many tickets are in route', async() => {
|
||||
const result = await nightmare
|
||||
.countElement('vn-route-tickets vn-textfield[model="ticket.priority"]');
|
||||
.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]');
|
||||
|
||||
expect(result).toEqual(11);
|
||||
});
|
||||
|
@ -74,7 +74,7 @@ xdescribe('Route basic Data path', () => {
|
|||
|
||||
it('should now count how many tickets are in route to find one less', async() => {
|
||||
const result = await nightmare
|
||||
.countElement('vn-route-tickets vn-textfield[model="ticket.priority"]');
|
||||
.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]');
|
||||
|
||||
expect(result).toEqual(9);
|
||||
});
|
||||
|
|
|
@ -32,6 +32,7 @@ export default class Field extends FormInput {
|
|||
}
|
||||
|
||||
set field(value) {
|
||||
if (value === this.field) return;
|
||||
super.field = value;
|
||||
this.classList.toggle('not-empty', value != null && value !== '');
|
||||
this.validateValue();
|
||||
|
@ -149,20 +150,28 @@ export default class Field extends FormInput {
|
|||
}
|
||||
|
||||
set error(value) {
|
||||
if (value === this.error) return;
|
||||
this._error = value;
|
||||
this.refreshHint();
|
||||
this.classList.toggle('invalid', Boolean(value));
|
||||
}
|
||||
|
||||
get error() {
|
||||
return this._error;
|
||||
}
|
||||
|
||||
get shownError() {
|
||||
return this.error || this.inputError || null;
|
||||
}
|
||||
|
||||
refreshHint() {
|
||||
let hint = this.error || this.hint || '';
|
||||
let error = this.shownError;
|
||||
let hint = error || this.hint;
|
||||
|
||||
let hintEl = this.element.querySelector('.hint');
|
||||
hintEl.innerText = hint;
|
||||
hintEl.innerText = hint || '';
|
||||
hintEl.classList.toggle('filled', Boolean(hint));
|
||||
|
||||
this.classList.toggle('invalid', Boolean(error));
|
||||
}
|
||||
|
||||
refreshFix(selector, text) {
|
||||
|
@ -205,18 +214,21 @@ export default class Field extends FormInput {
|
|||
}
|
||||
|
||||
buildInput(type) {
|
||||
let template = `<input ng-model="$ctrl.field"></input>`;
|
||||
let template = `<input type="${type}" ng-model="$ctrl.field"></input>`;
|
||||
this.input = this.$compile(template)(this.$)[0];
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* If input value is invalid, sets the error message as hint.
|
||||
*/
|
||||
validateValue() {
|
||||
this.error = this.input.checkValidity()
|
||||
let error = this.input.checkValidity()
|
||||
? null
|
||||
: this.input.validationMessage;
|
||||
|
||||
if (error === this.inputError) return;
|
||||
this.inputError = error;
|
||||
this.refreshHint();
|
||||
}
|
||||
}
|
||||
Field.$inject = ['$element', '$scope', '$compile'];
|
||||
|
@ -239,8 +251,7 @@ ngModule.vnComponent('vnField', {
|
|||
hint: '@?',
|
||||
error: '<?',
|
||||
tabIndex: '<?',
|
||||
onChange: '&?', // FIXME: Not implemented, nesessary?
|
||||
rule: '@?' // FIXME: Not implemented
|
||||
rule: '@?'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -3,15 +3,13 @@ import Input from '../../lib/input';
|
|||
import './style.scss';
|
||||
|
||||
export default class InputFile extends Input {
|
||||
constructor($element, $scope, $attrs, vnTemplate) {
|
||||
constructor($element, $scope) {
|
||||
super($element, $scope);
|
||||
this.element = $element[0];
|
||||
this.hasFocus = false;
|
||||
this._multiple = false;
|
||||
this._value = 'Select a file';
|
||||
|
||||
vnTemplate.normalizeInputAttrs($attrs);
|
||||
|
||||
this.registerEvents();
|
||||
}
|
||||
|
||||
|
@ -108,7 +106,7 @@ export default class InputFile extends Input {
|
|||
}
|
||||
}
|
||||
|
||||
InputFile.$inject = ['$element', '$scope', '$attrs', 'vnTemplate'];
|
||||
InputFile.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.component('vnInputFile', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -23,15 +23,15 @@ describe('Component vnInputNumber', () => {
|
|||
$ctrl.min = 0;
|
||||
|
||||
// FIXME: Input validation doesn't work with Jest?
|
||||
// expect($ctrl.error).toContain('Please select a value that is no less than 0');
|
||||
expect($ctrl.error).toBeNull();
|
||||
// expect($ctrl.shownError).toContain('Please select a value that is no less than 0');
|
||||
expect($ctrl.shownError).toBeNull();
|
||||
});
|
||||
|
||||
it(`should unset error property when value is upper than min`, () => {
|
||||
$ctrl.field = 1;
|
||||
$ctrl.min = 0;
|
||||
|
||||
expect($ctrl.error).toBeNull();
|
||||
expect($ctrl.shownError).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -41,8 +41,8 @@ describe('Component vnInputNumber', () => {
|
|||
$ctrl.max = 0;
|
||||
|
||||
// FIXME: Input validation doesn't work with Jest?
|
||||
// expect($ctrl.error).toContain('Please select a value that is no more than 0');
|
||||
expect($ctrl.error).toBeNull();
|
||||
// expect($ctrl.shownError).toContain('Please select a value that is no more than 0');
|
||||
expect($ctrl.shownError).toBeNull();
|
||||
});
|
||||
|
||||
// FIXME: Input validation doesn't work with Jest?
|
||||
|
@ -50,7 +50,7 @@ describe('Component vnInputNumber', () => {
|
|||
$ctrl.field = -1;
|
||||
$ctrl.min = 0;
|
||||
|
||||
expect($ctrl.error).toBeNull();
|
||||
expect($ctrl.shownError).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
<div class="table" ng-transclude>
|
||||
<div class="vn-table" ng-transclude>
|
||||
</div>
|
|
@ -5,181 +5,169 @@ vn-table {
|
|||
display: block;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.vn-table {
|
||||
width: 100%;
|
||||
display: table;
|
||||
border-collapse: collapse;
|
||||
|
||||
& > div {
|
||||
width: inherit;
|
||||
display: table;
|
||||
border-collapse: collapse;
|
||||
& > vn-thead,
|
||||
& > thead {
|
||||
display: table-header-group;
|
||||
border-bottom: .15em solid $color-spacer;
|
||||
|
||||
& > vn-thead {
|
||||
display: table-header-group;
|
||||
border-bottom: .15em solid $color-spacer;
|
||||
& > * > th {
|
||||
font-weight: normal;
|
||||
}
|
||||
& > * > vn-th[field] {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
cursor: pointer;
|
||||
|
||||
& > * > vn-th[field] {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
cursor: pointer;
|
||||
|
||||
&.active > :after {
|
||||
color: $color-font;
|
||||
opacity: 1;
|
||||
}
|
||||
&.desc > :after {
|
||||
content: 'arrow_drop_down';
|
||||
}
|
||||
&.asc > :after {
|
||||
content: 'arrow_drop_up';
|
||||
}
|
||||
& > :after {
|
||||
font-family: 'Material Icons';
|
||||
content: 'arrow_drop_down';
|
||||
position: absolute;
|
||||
color: $color-spacer;
|
||||
opacity: 0;
|
||||
}
|
||||
&:hover > :after {
|
||||
opacity: 1;
|
||||
}
|
||||
&.active > :after {
|
||||
color: $color-font;
|
||||
opacity: 1;
|
||||
}
|
||||
&.desc > :after {
|
||||
content: 'arrow_drop_down';
|
||||
}
|
||||
&.asc > :after {
|
||||
content: 'arrow_drop_up';
|
||||
}
|
||||
& > :after {
|
||||
font-family: 'Material Icons';
|
||||
content: 'arrow_drop_down';
|
||||
position: absolute;
|
||||
color: $color-spacer;
|
||||
opacity: 0;
|
||||
}
|
||||
&:hover > :after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
& > vn-tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
& > vn-tfoot {
|
||||
border-top: .15em solid $color-spacer;
|
||||
display: table-footer-group
|
||||
}
|
||||
& > * > vn-tr,
|
||||
& > * > a.vn-tr {
|
||||
}
|
||||
& > vn-tbody,
|
||||
& > tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
& > vn-tfoot,
|
||||
& > tfoot {
|
||||
border-top: .15em solid $color-spacer;
|
||||
display: table-footer-group
|
||||
}
|
||||
& > * > vn-tr,
|
||||
& > * > a.vn-tr,
|
||||
& > * > tr {
|
||||
display: table-row;
|
||||
height: 3em;
|
||||
}
|
||||
vn-thead, vn-tbody, vn-tfoot,
|
||||
thead, tbody, tfoot {
|
||||
& > * {
|
||||
display: table-row;
|
||||
height: 3em;
|
||||
}
|
||||
vn-thead, vn-tbody, vn-tfoot {
|
||||
& > * {
|
||||
display: table-row;
|
||||
|
||||
& > vn-th {
|
||||
color: $color-font-light;
|
||||
padding-top: 1em;
|
||||
padding-bottom: .8em;
|
||||
& > vn-th,
|
||||
& > th {
|
||||
color: $color-font-light;
|
||||
padding-top: 1em;
|
||||
padding-bottom: .8em;
|
||||
}
|
||||
& > vn-th,
|
||||
& > vn-td,
|
||||
& > th,
|
||||
& > td {
|
||||
overflow: hidden;
|
||||
}
|
||||
& > vn-th,
|
||||
& > vn-td,
|
||||
& > vn-td-editable,
|
||||
& > th,
|
||||
& > td {
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
padding: .6em .5em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 5em;
|
||||
|
||||
&[number] {
|
||||
text-align: right;
|
||||
width: 6em;
|
||||
}
|
||||
& > vn-th,
|
||||
& > vn-td {
|
||||
overflow: hidden;
|
||||
&[center] {
|
||||
text-align: center;
|
||||
}
|
||||
& > vn-th,
|
||||
& > vn-td,
|
||||
& > vn-td-editable {
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
padding: .6em .5em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 5em;
|
||||
|
||||
&[number] {
|
||||
text-align: right;
|
||||
width: 6em;
|
||||
}
|
||||
&[center] {
|
||||
text-align: center;
|
||||
}
|
||||
&[shrink] {
|
||||
width: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
&[expand] {
|
||||
max-width: 10em;
|
||||
min-width: 0;
|
||||
}
|
||||
vn-icon.bright, i.bright {
|
||||
color: #f7931e;
|
||||
}
|
||||
&[shrink] {
|
||||
width: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
& > :last-child {
|
||||
padding-right: 1.4em;
|
||||
&[expand] {
|
||||
max-width: 10em;
|
||||
min-width: 0;
|
||||
}
|
||||
& > :first-child {
|
||||
padding-left: 1.4em;
|
||||
vn-icon.bright, i.bright {
|
||||
color: #f7931e;
|
||||
}
|
||||
}
|
||||
& > a.vn-tr {
|
||||
color: inherit;
|
||||
& > :last-child {
|
||||
padding-right: 1.4em;
|
||||
}
|
||||
& > :first-child {
|
||||
padding-left: 1.4em;
|
||||
}
|
||||
}
|
||||
vn-tbody > * {
|
||||
border-bottom: .1em solid $color-spacer-light;
|
||||
& > a.vn-tr {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
vn-tbody > *,
|
||||
tbody > * {
|
||||
border-bottom: .1em solid $color-spacer-light;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
}
|
||||
& > vn-td .chip {
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
}
|
||||
& > vn-td,
|
||||
& > td {
|
||||
.chip {
|
||||
padding: .3em;
|
||||
border-radius: .3em
|
||||
}
|
||||
|
||||
& > vn-td .chip.notice {
|
||||
border-radius: .3em;
|
||||
color: $color-font-bg;
|
||||
background-color: $color-notice-medium
|
||||
}
|
||||
|
||||
& > vn-td .chip.success {
|
||||
color: $color-font-bg;
|
||||
background-color: $color-success-medium
|
||||
&.notice {
|
||||
background-color: $color-notice-medium
|
||||
}
|
||||
&.success {
|
||||
background-color: $color-success-medium;
|
||||
}
|
||||
&.warning {
|
||||
background-color: $color-main-medium;
|
||||
}
|
||||
&.alert {
|
||||
background-color: $color-alert-medium;
|
||||
}
|
||||
&.message {
|
||||
color: $color-font-dark;
|
||||
background-color: $color-bg-dark
|
||||
}
|
||||
}
|
||||
|
||||
& > vn-td .chip.warning {
|
||||
color: $color-font-bg;
|
||||
background-color: $color-main-medium;
|
||||
}
|
||||
|
||||
& > vn-td .chip.alert {
|
||||
color: $color-font-bg;
|
||||
background-color: $color-alert-medium;
|
||||
}
|
||||
|
||||
& > vn-td .chip.message {
|
||||
color: $color-font-dark;
|
||||
background-color: $color-bg-dark
|
||||
}
|
||||
|
||||
& > vn-td vn-icon-menu {
|
||||
vn-icon-menu {
|
||||
display: inline-block;
|
||||
color: $color-main;
|
||||
padding: .25em
|
||||
}
|
||||
}
|
||||
& > [actions] {
|
||||
width: 1px;
|
||||
|
||||
& > [actions] {
|
||||
width: 1px;
|
||||
|
||||
& > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
& > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
& > vn-empty-rows {
|
||||
display: table-caption;
|
||||
caption-side: bottom;
|
||||
text-align: center;
|
||||
padding: 1.5em;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
vn-autocomplete {
|
||||
div.mdl-textfield {
|
||||
padding: 0 !important;
|
||||
}
|
||||
label.mdl-textfield__label:after {
|
||||
bottom: 0;
|
||||
}
|
||||
div.icons {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
vn-textfield {
|
||||
float: right;
|
||||
|
|
|
@ -2,7 +2,7 @@ import './id';
|
|||
import './focus';
|
||||
import './dialog';
|
||||
import './popover';
|
||||
import './validation';
|
||||
import './rule';
|
||||
import './acl';
|
||||
import './on-error-src';
|
||||
import './zoom-image';
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import ngModule from '../module';
|
||||
import {validateAll} from '../lib/validator';
|
||||
import {firstUpper} from '../lib/string';
|
||||
|
||||
directive.$inject = ['$translate', '$window'];
|
||||
export function directive($translate, $window) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: link,
|
||||
require: {
|
||||
ngModel: 'ngModel',
|
||||
form: '^^?form'
|
||||
}
|
||||
};
|
||||
|
||||
function link($scope, $element, $attrs, $ctrl) {
|
||||
let vnValidations = $window.validations;
|
||||
if (!vnValidations) return;
|
||||
|
||||
if (!/^([A-Z]\w+(\.[a-z]\w*)?)?$/.test($attrs.rule))
|
||||
throw new Error(`rule: Attribute must have this syntax: [ModelName[.fieldName]]`);
|
||||
|
||||
let rule = $attrs.rule.split('.');
|
||||
let modelName = rule.shift();
|
||||
let fieldName = rule.shift();
|
||||
|
||||
let split = $attrs.ngModel.split('.');
|
||||
if (!fieldName) fieldName = split.pop() || null;
|
||||
if (!modelName) modelName = firstUpper(split.pop() || '');
|
||||
|
||||
if (!modelName || !fieldName)
|
||||
throw new Error(`rule: Cannot retrieve model or field attribute`);
|
||||
|
||||
let modelValidations = vnValidations[modelName];
|
||||
|
||||
if (!modelValidations)
|
||||
throw new Error(`rule: Model '${modelName}' doesn't exist`);
|
||||
|
||||
let validations = modelValidations.validations[fieldName];
|
||||
if (!validations || validations.length == 0)
|
||||
return;
|
||||
|
||||
let ngModel = $ctrl.ngModel;
|
||||
let form = $ctrl.form;
|
||||
let field = $element[0].$ctrl;
|
||||
let error;
|
||||
|
||||
function refreshError() {
|
||||
if (!field) return;
|
||||
let canShow = ngModel.$dirty || (form && form.$submitted);
|
||||
field.error = error && canShow ? error.message : null;
|
||||
}
|
||||
|
||||
ngModel.$options.$$options.allowInvalid = true;
|
||||
ngModel.$validators.entity = value => {
|
||||
try {
|
||||
error = null;
|
||||
validateAll($translate, value, validations);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
refreshError();
|
||||
return error == null;
|
||||
};
|
||||
|
||||
if (form)
|
||||
$scope.$watch(form.$submitted, refreshError);
|
||||
}
|
||||
}
|
||||
ngModule.directive('rule', directive);
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
describe('Directive rule', () => {
|
||||
let $scope;
|
||||
let $element;
|
||||
let element;
|
||||
|
||||
beforeEach(angular.mock.module('vnCore', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
function compile(html, value) {
|
||||
inject(($compile, $rootScope, $window) => {
|
||||
$window.validations = {Model:
|
||||
{validations: {field: [{validation: 'absence'}]}}
|
||||
};
|
||||
|
||||
$scope = $rootScope.$new();
|
||||
|
||||
$element = angular.element(html);
|
||||
$compile($element)($scope);
|
||||
element = $element[0];
|
||||
|
||||
$scope.model = {field: value};
|
||||
$scope.$digest();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
$element.remove();
|
||||
});
|
||||
|
||||
describe('Errors', () => {
|
||||
it(`should throw an error if the rule doesn't have the right syntax`, () => {
|
||||
expect(() => {
|
||||
compile(`
|
||||
<form>
|
||||
<input
|
||||
type="text"
|
||||
ng-model="model.field"
|
||||
rule="invalidLowerCamelCaseModel">
|
||||
</input>
|
||||
</form>
|
||||
`);
|
||||
}).toThrow(new Error(`rule: Attribute must have this syntax: [ModelName[.fieldName]]`));
|
||||
});
|
||||
|
||||
it('should throw an error if cannot retrieve model or field', () => {
|
||||
expect(() => {
|
||||
compile(`
|
||||
<form>
|
||||
<input
|
||||
type="text"
|
||||
ng-model="model"
|
||||
rule>
|
||||
</input>
|
||||
</form>
|
||||
`);
|
||||
}).toThrow(new Error(`rule: Cannot retrieve model or field attribute`));
|
||||
});
|
||||
|
||||
it('should throw an error if the model is not defined', () => {
|
||||
expect(() => {
|
||||
compile(`
|
||||
<form>
|
||||
<input
|
||||
type="text"
|
||||
ng-model="model.field"
|
||||
rule="NonExistentModel.field">
|
||||
</input>
|
||||
</form>
|
||||
`);
|
||||
}).toThrow(new Error(`rule: Model 'NonExistentModel' doesn't exist`));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator extended', () => {
|
||||
let html = `
|
||||
<form>
|
||||
<input
|
||||
type="text"
|
||||
ng-model="model.field"
|
||||
rule="Model.field">
|
||||
</input>
|
||||
</form>
|
||||
`;
|
||||
|
||||
it('should not validate the entity as it has a wrong value', () => {
|
||||
compile(html, 'invalidValue');
|
||||
|
||||
expect(element.classList).toContain('ng-invalid');
|
||||
});
|
||||
|
||||
it('should validate the entity as it has a valid value', () => {
|
||||
compile(html, '');
|
||||
|
||||
expect(element.classList).toContain('ng-valid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator minimal', () => {
|
||||
let html = `
|
||||
<input
|
||||
type="text"
|
||||
ng-model="model.field"
|
||||
rule>
|
||||
</input>
|
||||
`;
|
||||
|
||||
it('should validate with empty rule and without specifying a parent form', () => {
|
||||
compile(html, 'invalidValue');
|
||||
|
||||
expect(element.classList).toContain('ng-invalid');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,186 +0,0 @@
|
|||
describe('Directive validation', () => {
|
||||
let scope;
|
||||
let element;
|
||||
let compile;
|
||||
|
||||
beforeEach(angular.mock.module('vnCore', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
compile = (_element, validations, value) => {
|
||||
inject(($compile, $rootScope, $window) => {
|
||||
$window.validations = validations;
|
||||
scope = $rootScope.$new();
|
||||
scope.user = {name: value};
|
||||
element = angular.element(_element);
|
||||
$compile(element)(scope);
|
||||
scope.$digest();
|
||||
});
|
||||
};
|
||||
|
||||
it(`should throw an error if the vnValidation doesn't have the right syntax`, () => {
|
||||
let html = `<input type="name" ng-model="user.name" vn-validation="user"/>`;
|
||||
|
||||
expect(() => {
|
||||
compile(html, {});
|
||||
}).toThrow(new Error(`vnValidation: Attribute must have this syntax: [entity].[field]`));
|
||||
});
|
||||
|
||||
it('should throw an error if the window.validations aint defined', () => {
|
||||
let html = `<input type="name" ng-model="user.name" vn-validation="user.name"/>`;
|
||||
|
||||
expect(() => {
|
||||
compile(html, {});
|
||||
}).toThrow(new Error(`vnValidation: Entity 'User' doesn't exist`));
|
||||
});
|
||||
|
||||
describe('Validator presence()', () => {
|
||||
it('should not validate the user name as it is an empty string', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'presence'}]}}};
|
||||
compile(html, validations, 'Spiderman');
|
||||
scope.user.name = '';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator absence()', () => {
|
||||
it('should not validate the entity as it should be an empty string', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'absence'}]}}};
|
||||
compile(html, validations, 'Spiderman');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
|
||||
it('should validate the entity as it is an empty string', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'absence'}]}}};
|
||||
compile(html, validations, '');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-valid');
|
||||
expect(element[0].classList).not.toContain('ng-invalid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator length()', () => {
|
||||
it('should not validate the user name as it should have min length of 15', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'length', min: 10, max: 50, is: 15}]}}};
|
||||
compile(html, validations, 'fifteen!');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
|
||||
it('should validate the user name as it has length of 15', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'length', min: 10, max: 50, is: 15}]}}};
|
||||
compile(html, validations, 'fifteen length!');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-valid');
|
||||
expect(element[0].classList).not.toContain('ng-invalid');
|
||||
});
|
||||
|
||||
it('should not validate the user name as it should have min length of 10', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'length', min: 10}]}}};
|
||||
compile(html, validations, 'shortname');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
|
||||
it('should validate the user name as its length is greater then the minimum', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'length', min: 10}]}}};
|
||||
compile(html, validations, 'verylongname');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-valid');
|
||||
expect(element[0].classList).not.toContain('ng-invalid');
|
||||
});
|
||||
|
||||
it('should not validate the user name as its length is greater then the maximum', () => {
|
||||
let html = `<form><input type="name" ng-model="user.name" vn-validation="user.name"/></form>`;
|
||||
let validations = {User: {validations: {name: [{validation: 'length', max: 10}]}}};
|
||||
compile(html, validations, 'toolongname');
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator numericality()', () => {
|
||||
it('should not validate the phone number as it should a integer', () => {
|
||||
let html = `<form><input type="text" ng-model="user.phone" vn-validation="user.phone"/></form>`;
|
||||
let validations = {User: {validations: {phone: [{validation: 'numericality', is: 'what is this?'}]}}};
|
||||
compile(html, validations, 'spiderman');
|
||||
scope.user.phone = 'this is not a phone number!';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
|
||||
it('should validate the phone number as it an integer', () => {
|
||||
let html = `<form><input type="text" ng-model="user.phone" vn-validation="user.phone"/></form>`;
|
||||
let validations = {User: {validations: {phone: [{validation: 'numericality', is: 'what is this?'}]}}};
|
||||
compile(html, validations, 'spiderman');
|
||||
scope.user.phone = '555555555';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-valid');
|
||||
expect(element[0].classList).not.toContain('ng-invalid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator inclusion()', () => {
|
||||
it('should not validate the phone number as it is not an integer', () => {
|
||||
let html = `<form><input type="text" ng-model="user.phone" vn-validation="user.phone"/></form>`;
|
||||
let validations = {User: {validations: {phone: [{validation: 'inclusion'}]}}};
|
||||
compile(html, validations, 'spiderman');
|
||||
scope.user.phone = 'this is not a phone number!';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator exclusion()', () => {
|
||||
it('should validate the phone number as it is an integer', () => {
|
||||
let html = `<form><input type="text" ng-model="user.phone" vn-validation="user.phone"/></form>`;
|
||||
let validations = {User: {validations: {phone: [{validation: 'exclusion'}]}}};
|
||||
compile(html, validations, 'spiderman');
|
||||
scope.user.phone = '555555555';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-valid');
|
||||
expect(element[0].classList).not.toContain('ng-invalid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validator format()', () => {
|
||||
it('should not validate the email number as it doesnt contain @', () => {
|
||||
let html = `<form><input type="text" ng-model="user.email" vn-validation="user.email"/></form>`;
|
||||
let validations = {User: {validations: {email: [{validation: 'format', with: '@'}]}}};
|
||||
compile(html, validations, 'spiderman');
|
||||
scope.user.email = 'userverdnatura.es';
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0].classList).toContain('ng-invalid');
|
||||
expect(element[0].classList).not.toContain('ng-valid');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,80 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import {validateAll} from '../lib/validator';
|
||||
import {firstUpper} from '../lib/string';
|
||||
|
||||
directive.$inject = ['$interpolate', '$compile', '$translate', '$window'];
|
||||
export function directive(interpolate, compile, $translate, $window) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: ['ngModel', '^^?form'],
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
let vnValidations = $window.validations;
|
||||
|
||||
if (!attrs.vnValidation || !vnValidations)
|
||||
return;
|
||||
|
||||
let split = attrs.vnValidation.split('.');
|
||||
|
||||
if (split.length !== 2)
|
||||
throw new Error(`vnValidation: Attribute must have this syntax: [entity].[field]`);
|
||||
|
||||
let entityName = firstUpper(split[0]);
|
||||
let fieldName = split[1];
|
||||
let entity = vnValidations[entityName];
|
||||
|
||||
if (!entity)
|
||||
throw new Error(`vnValidation: Entity '${entityName}' doesn't exist`);
|
||||
|
||||
let validations = entity.validations[fieldName];
|
||||
if (!validations || validations.length == 0)
|
||||
return;
|
||||
|
||||
let ngModel = ctrl[0];
|
||||
let form = ctrl[1];
|
||||
let errorSpan = angular.element('<span class="mdl-textfield__error"></span>');
|
||||
let errorMsg;
|
||||
let errorShown = false;
|
||||
|
||||
ngModel.$options.$$options.allowInvalid = true;
|
||||
ngModel.$validators.entity = value => {
|
||||
try {
|
||||
validateAll($translate, value, validations);
|
||||
return true;
|
||||
} catch (e) {
|
||||
errorMsg = e.message;
|
||||
if (errorShown) changeError();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch(() => {
|
||||
return (form.$submitted || ngModel.$dirty) && ngModel.$invalid;
|
||||
}, value => {
|
||||
let parent = element.parent();
|
||||
|
||||
if (value) {
|
||||
changeError();
|
||||
parent.addClass('invalid');
|
||||
element.after(errorSpan);
|
||||
} else if (errorShown) {
|
||||
parent.removeClass('invalid');
|
||||
parent.removeAttr('title');
|
||||
errorSpan.remove();
|
||||
errorSpan.empty();
|
||||
}
|
||||
|
||||
errorShown = value;
|
||||
});
|
||||
|
||||
function changeError() {
|
||||
let parent = element.parent();
|
||||
errorSpan.text(errorMsg);
|
||||
parent.attr('title', errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
ngModule.directive('vnValidation', directive);
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
import './module-loader';
|
||||
import './crud';
|
||||
import './acl-service';
|
||||
import './template';
|
||||
import './copy';
|
||||
import './equals';
|
||||
import './modified';
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
import {validate} from '../validator.js';
|
||||
|
||||
describe('Validator', () => {
|
||||
let $translate;
|
||||
|
||||
beforeEach(angular.mock.module('vnCore', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
beforeEach(inject(_$translate_ => {
|
||||
$translate = _$translate_;
|
||||
}));
|
||||
|
||||
describe('presence', () => {
|
||||
let conf = {validation: 'presence'};
|
||||
|
||||
it('should not validate the value as it should be defined', () => {
|
||||
expect(() => {
|
||||
validate($translate, '', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should be defined', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'aDefinedValue', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('absence', () => {
|
||||
let conf = {validation: 'absence'};
|
||||
|
||||
it('should not validate the value as it should be undefined', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'aDefinedValue', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should be undefined', () => {
|
||||
expect(() => {
|
||||
validate($translate, '', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('length', () => {
|
||||
it('should not validate the value as it should have an specific valid length', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
is: 25
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'invalidSpecificLengthString', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should have an specific valid length', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
is: 25
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'validSpecificLengthString', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
it('should not validate the value as it should have a min length', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
min: 10
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'shortName', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should have a min length', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
min: 10
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'veryLongName', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
it('should not validate the value as it should be smaller than the maximum', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
max: 20
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'chainThatExceedsMaxLength', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should be smaller than the maximum', () => {
|
||||
let conf = {
|
||||
validation: 'length',
|
||||
max: 20
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validate($translate, 'shortString', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('numericality', () => {
|
||||
let conf = {validation: 'numericality'};
|
||||
|
||||
it('should not validate the value as it should be an integer', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'notANumber', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should be an integer', () => {
|
||||
expect(() => {
|
||||
validate($translate, '123456789', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('inclusion', () => {
|
||||
let conf = {
|
||||
validation: 'inclusion',
|
||||
in: ['firstValue', 'seekValue', 'lastValue']
|
||||
};
|
||||
|
||||
it('should not validate the value as it should be in array', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'notIncludedValue', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should be in array', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'seekValue', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('exclusion', () => {
|
||||
let conf = {
|
||||
validation: 'exclusion',
|
||||
in: ['firstValue', 'seekValue', 'lastValue']
|
||||
};
|
||||
|
||||
it('should not validate the value as it should not be in array', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'seekValue', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should not be in array', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'notIncludedValue', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('format', () => {
|
||||
let conf = {
|
||||
validation: 'format',
|
||||
with: /[a-z-]+@[a-z-]+\.[a-z]+/
|
||||
};
|
||||
|
||||
it('should not validate the value as it should match regexp', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'wrongValue', conf);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('should validate the value as it should match regexp', () => {
|
||||
expect(() => {
|
||||
validate($translate, 'valid-value@domain.com', conf);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@
|
|||
* @return {String} The camelized string
|
||||
*/
|
||||
export function kebabToCamel(str) {
|
||||
var camelCased = str.replace(/-([a-z])/g, function(g) {
|
||||
let camelCased = str.replace(/-([a-z])/g, function(g) {
|
||||
return g[1].toUpperCase();
|
||||
});
|
||||
return camelCased;
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Template {
|
||||
getNormalized(template, $attrs, defaults) {
|
||||
this.normalizeInputAttrs($attrs);
|
||||
return this.get(template, $attrs, defaults);
|
||||
}
|
||||
normalizeInputAttrs($attrs) {
|
||||
const field = $attrs.field || $attrs.model;
|
||||
const split = field.split('.');
|
||||
const len = split.length;
|
||||
|
||||
let i = len - 1;
|
||||
const fieldName = split[i--];
|
||||
const entity = i >= 0 ? split[i--] : 'model';
|
||||
const ctrl = i >= 0 ? split[i--] : '$ctrl';
|
||||
|
||||
if ($attrs.field) {
|
||||
if (len == 0)
|
||||
throw new Error(`Attribute 'field' can not be empty`);
|
||||
if (len > 3)
|
||||
throw new Error(`Attribute 'field' must have this syntax: [ctrl].[entity].[field]`);
|
||||
|
||||
if ($attrs.model === undefined)
|
||||
$attrs.model = `${ctrl}.${entity}.${fieldName}`;
|
||||
if ($attrs.rule === undefined && len >= 2)
|
||||
$attrs.rule = `${entity}.${fieldName}`;
|
||||
if ($attrs.label === undefined && len >= 2)
|
||||
$attrs.label = `${entity}.${fieldName}`;
|
||||
}
|
||||
|
||||
if ($attrs.name === undefined)
|
||||
$attrs.name = fieldName;
|
||||
|
||||
if ($attrs.focus !== undefined)
|
||||
$attrs.focus = 'vn-focus';
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.service('vnTemplate', Template);
|
|
@ -9,9 +9,9 @@ export default class Config {
|
|||
$http,
|
||||
vnApp,
|
||||
$translate,
|
||||
storage: $window.localStorage,
|
||||
user: {},
|
||||
local: {},
|
||||
storage: $window.localStorage
|
||||
local: {}
|
||||
});
|
||||
|
||||
this.params = [
|
||||
|
@ -29,8 +29,8 @@ export default class Config {
|
|||
.then(res => {
|
||||
for (let param of this.params)
|
||||
this.user[param] = res.data[param];
|
||||
this.mergeParams();
|
||||
});
|
||||
})
|
||||
.finally(() => this.mergeParams());
|
||||
}
|
||||
|
||||
mergeParams() {
|
||||
|
@ -47,13 +47,19 @@ export default class Config {
|
|||
this.mergeParams();
|
||||
|
||||
let params = {[param]: value};
|
||||
return this.$http.post('api/UserConfigs/setUserConfig', params);
|
||||
return this.$http.post('api/UserConfigs/setUserConfig', params)
|
||||
.then(() => this.showSaved());
|
||||
}
|
||||
|
||||
setLocal(param, value) {
|
||||
this.setItem(param, value);
|
||||
this.local[param] = value;
|
||||
this.mergeParams();
|
||||
this.showSaved();
|
||||
}
|
||||
|
||||
showSaved() {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
}
|
||||
|
||||
getItem(key) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
import './acl-service';
|
||||
import './app';
|
||||
import './auth';
|
||||
import './token';
|
||||
|
|
|
@ -62,7 +62,7 @@ export function config($translatePartialLoaderProvider, $httpProvider, $compileP
|
|||
$translatePartialLoaderProvider.addPart(appName);
|
||||
$httpProvider.interceptors.push('vnInterceptor');
|
||||
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
// $compileProvider.debugInfoEnabled(false);
|
||||
$compileProvider.commentDirectivesEnabled(false);
|
||||
$compileProvider.cssClassDirectivesEnabled(false);
|
||||
}
|
||||
|
|
|
@ -116,52 +116,6 @@ html [scrollable] {
|
|||
margin-right: auto;
|
||||
max-width: $width-md;
|
||||
}
|
||||
|
||||
.vn-grid {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
|
||||
& > thead,
|
||||
& > tbody,
|
||||
& > tfoot {
|
||||
tr {
|
||||
td, th {
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
|
||||
&[number]{
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
& > thead, & > tbody {
|
||||
border-bottom: 3px solid $color-spacer;
|
||||
}
|
||||
& > tbody > tr {
|
||||
border-bottom: 1px solid $color-spacer;
|
||||
transition: background-color 200ms ease-in-out;
|
||||
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
}
|
||||
&.success {
|
||||
background-color: rgba(163, 209, 49, 0.3);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(163, 209, 49, 0.5);
|
||||
}
|
||||
}
|
||||
&.warning {
|
||||
background-color: rgba(247, 147, 30, 0.3);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(247, 147, 30, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vn-empty-rows {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
@ -180,12 +134,12 @@ vn-empty-rows {
|
|||
[uppercase], .uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
html [text-center], .text-center {
|
||||
html [text-center] {
|
||||
text-align: center;
|
||||
}
|
||||
html [text-right], .text-right {
|
||||
html [text-right] {
|
||||
text-align: right;
|
||||
}
|
||||
html [text-left], .text-left {
|
||||
html [text-left] {
|
||||
text-align: left;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
<form
|
||||
name="form"
|
||||
ng-submit="$ctrl.onSubmit()"
|
||||
class="vn-w-md"
|
||||
rule="Zone">
|
||||
class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
vn-id="watcher"
|
||||
data="$ctrl.zone"
|
||||
form="form"
|
||||
save="post"
|
||||
rule="Zone">
|
||||
save="post">
|
||||
</vn-watcher>
|
||||
<div class="content-block">
|
||||
<form name="form" vn-http-submit="$ctrl.onSubmit()" compact>
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
</vn-watcher>
|
||||
<form
|
||||
name="form"
|
||||
ng-submit="$ctrl.onSubmit()"
|
||||
rule="Zone">
|
||||
ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
<!-- Transfer Popover -->
|
||||
<vn-popover class="lastTicketsPopover" vn-id="lastTicketsPopover">
|
||||
<div class="ticketList vn-pa-md">
|
||||
<vn-table model="lastTicketsModel" auto-load="false" class="vn-grid">
|
||||
<vn-table model="lastTicketsModel" auto-load="false">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>ID</vn-th>
|
||||
|
|
|
@ -146,7 +146,7 @@
|
|||
vn-two
|
||||
label="Description"
|
||||
ng-model="observation.description"
|
||||
rule="addressObservation.description">
|
||||
rule="AddressObservation">
|
||||
</vn-textfield>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
vn-one
|
||||
label="Name"
|
||||
ng-model="contact.name"
|
||||
rule="clientContact.name">
|
||||
rule="ClientContact">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Phone"
|
||||
ng-model="contact.phone"
|
||||
rule="clientContact.phone"
|
||||
rule="ClientContact"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-none>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
min="0"
|
||||
label="Credit"
|
||||
ng-model="$ctrl.creditClassification.credit"
|
||||
rule="creditInsurance.credit"
|
||||
rule
|
||||
vn-focus>
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
|
@ -15,7 +15,7 @@
|
|||
step="1"
|
||||
label="Grade"
|
||||
ng-model="$ctrl.creditClassification.grade"
|
||||
rule="CreditInsurance.grade">
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
min="0"
|
||||
label="Credit"
|
||||
ng-model="$ctrl.insurance.credit"
|
||||
rule="CreditInsurance.credit"
|
||||
rule="CreditInsurance"
|
||||
vn-focus>
|
||||
</vn-input-number>
|
||||
<vn-date-picker
|
||||
|
@ -29,7 +29,7 @@
|
|||
step="1"
|
||||
label="Grade"
|
||||
ng-model="$ctrl.insurance.grade"
|
||||
rule="CreditInsurance.grade">
|
||||
rule="CreditInsurance">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
vn-focus
|
||||
label="Social name"
|
||||
ng-model="$ctrl.client.socialName"
|
||||
rule="client.socialName"
|
||||
rule
|
||||
info="You can use letters and spaces">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
vn-three
|
||||
label="Code"
|
||||
ng-model="niche.code"
|
||||
rule="itemNiche.code"
|
||||
rule="ItemNiche"
|
||||
vn-acl="buyer,replenisher">
|
||||
</vn-textfield>
|
||||
<vn-none>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
vn-three
|
||||
label="Value"
|
||||
ng-model="itemTag.value"
|
||||
rule="itemTag.value">
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-autocomplete
|
||||
ng-show="tag.selection.isFree === false"
|
||||
|
@ -57,7 +57,7 @@
|
|||
type="number"
|
||||
label="Relevancy"
|
||||
ng-model="itemTag.priority"
|
||||
rule="itemTag.priority">
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.summary.total | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
<vn-auto>
|
||||
<vn-table class="vn-grid">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink></vn-th>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
type="number"
|
||||
on-change="$ctrl.setPriority(ticket.id, ticket.priority)"
|
||||
ng-model="ticket.priority"
|
||||
rule="ticket.priority">
|
||||
rule="Ticket">
|
||||
</vn-textfield>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<form name="form">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<table class="vn-grid">
|
||||
<table class="vn-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number translate>Item</th>
|
||||
|
|
|
@ -6,72 +6,64 @@
|
|||
data="components"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<table class="vn-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number translate>Item</th>
|
||||
<th translate>Description</th>
|
||||
<th number translate>Quantity</th>
|
||||
<th translate>Serie</th>
|
||||
<th translate>Components</th>
|
||||
<th number translate>Import</th>
|
||||
<th number translate>Total import</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td number colspan="7">
|
||||
<span translate>Base to commission</span> {{$ctrl.base() | currency: 'EUR':3}}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody ng-repeat="sale in components track by sale.id">
|
||||
<tr>
|
||||
<td rowspan="{{::sale.components.length + 1}}" number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</td>
|
||||
<td rowspan="{{::sale.components.length + 1}}">
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</td>
|
||||
<td rowspan="{{::sale.components.length + 1}}" number>
|
||||
{{::sale.quantity}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
ng-repeat="component in sale.components track by component.componentFk">
|
||||
<td ng-class="::{first: $index == 0,last: $index == sale.components.length - 1}">
|
||||
{{::component.componentRate.componentType.type}}
|
||||
</td>
|
||||
<td ng-class="::{first: $index == 0,last: $index == sale.components.length - 1}">
|
||||
{{::component.componentRate.name}}
|
||||
</td>
|
||||
<td ng-class="::{first: $index == 0,last: $index == sale.components.length - 1}" number>
|
||||
{{::component.value | currency: 'EUR':3}}
|
||||
</td>
|
||||
<td ng-class="::{first: $index == 0,last: $index == sale.components.length - 1}" number>
|
||||
{{::sale.quantity * component.value | currency: 'EUR':3}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="model.data.length === 0" class="list list-element">
|
||||
<td colspan="7" style="text-align: center" translate>No results</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</vn-vertical>
|
||||
<vn-data-viewer model="model" class="vn-w-xl">
|
||||
<vn-card class="vn-pa-lg text-right" name="base-sum">
|
||||
<span translate>Base to commission</span> {{$ctrl.base() | currency: 'EUR':3}}
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
<vn-card class="vn-mt-md">
|
||||
<table class="vn-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number translate>Item</th>
|
||||
<th translate expand>Description</th>
|
||||
<th number translate>Quantity</th>
|
||||
<th translate>Serie</th>
|
||||
<th translate>Components</th>
|
||||
<th number translate>Import</th>
|
||||
<th number translate>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="sale in components track by sale.id">
|
||||
<tr style="height: initial;">
|
||||
<td rowspan="{{::sale.components.length + 1}}" number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</td>
|
||||
<td rowspan="{{::sale.components.length + 1}}" expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</td>
|
||||
<td rowspan="{{::sale.components.length + 1}}" number>
|
||||
{{::sale.quantity}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
ng-repeat="component in sale.components track by component.componentFk"
|
||||
class="components">
|
||||
<td>
|
||||
{{::component.componentRate.componentType.type}}
|
||||
</td>
|
||||
<td>
|
||||
{{::component.componentRate.name}}
|
||||
</td>
|
||||
<td number>
|
||||
{{::component.value | currency: 'EUR':3}}
|
||||
</td>
|
||||
<td number>
|
||||
{{::sale.quantity * component.value | currency: 'EUR':3}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
@import "variables";
|
||||
|
||||
vn-ticket-components {
|
||||
.vn-grid {
|
||||
tbody:not(:last-child) {
|
||||
.vn-table > tbody {
|
||||
&:not(:last-child) {
|
||||
border-bottom: .1em solid $color-spacer-light;
|
||||
}
|
||||
& > tr {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tfoot tr:first-child td {
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
|
||||
tr {
|
||||
td {
|
||||
padding-top: .1em !important;
|
||||
padding-bottom: .1em !important;
|
||||
&.components {
|
||||
height: 1em;
|
||||
|
||||
& > td {
|
||||
padding-top: .1em;
|
||||
padding-bottom: .1em;
|
||||
}
|
||||
&:nth-child(2) > td {
|
||||
padding-top: 1em;
|
||||
}
|
||||
&:last-child > td {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
td.first {
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
|
||||
td.last {
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
}
|
||||
tr:not(:first-child):not(:last-child), {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,101 +4,100 @@
|
|||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
filter="::$ctrl.filter"
|
||||
limit="20"
|
||||
data="$ctrl.ticketDms">
|
||||
data="$ctrl.ticketDms"
|
||||
order="dmsFk DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th>
|
||||
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
|
||||
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
|
||||
<vn-th field="reference" shrink>Reference</vn-th>
|
||||
<vn-th expand>Description</vn-th>
|
||||
<vn-th field="hasFile" shrink>Original</vn-th>
|
||||
<vn-th shrink>File</vn-th>
|
||||
<vn-th shrink>Employee</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="document in $ctrl.ticketDms">
|
||||
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.dmsType.name}}">
|
||||
{{::document.dms.dmsType.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink number>
|
||||
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
|
||||
ng-class="{'message': document.dms.hardCopyNumber}">
|
||||
{{::document.dms.hardCopyNumber}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.reference}}">
|
||||
{{::document.dms.reference}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<span title="{{::document.dms.description}}">
|
||||
{{::document.dms.description}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-check disabled="true"
|
||||
ng-model="document.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<a target="_blank"
|
||||
title="{{'Download file' | translate}}"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
{{::document.dms.file}}
|
||||
</a>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
|
||||
{{::document.dms.worker.user.nickname | dashIfEmpty}}
|
||||
</span></vn-td>
|
||||
<vn-td>
|
||||
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<a target="_blank"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
<vn-icon-button
|
||||
icon="cloud_download"
|
||||
title="{{'Download file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</a>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="edit"
|
||||
ui-sref="ticket.card.dms.edit({dmsId: {{::document.dmsFk}}})"
|
||||
title="{{'Edit file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="delete"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-lg">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="dmsFk" shrink>Id</vn-th>
|
||||
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
|
||||
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
|
||||
<vn-th field="reference" shrink>Reference</vn-th>
|
||||
<vn-th expand>Description</vn-th>
|
||||
<vn-th field="hasFile" shrink>Original</vn-th>
|
||||
<vn-th shrink>File</vn-th>
|
||||
<vn-th shrink>Employee</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="document in $ctrl.ticketDms">
|
||||
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.dmsType.name}}">
|
||||
{{::document.dms.dmsType.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink number>
|
||||
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
|
||||
ng-class="{'message': document.dms.hardCopyNumber}">
|
||||
{{::document.dms.hardCopyNumber}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span title="{{::document.dms.reference}}">
|
||||
{{::document.dms.reference}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<span title="{{::document.dms.description}}">
|
||||
{{::document.dms.description}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-check disabled="true"
|
||||
ng-model="document.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<a target="_blank"
|
||||
title="{{'Download file' | translate}}"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
{{::document.dms.file}}
|
||||
</a>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
|
||||
{{::document.dms.worker.user.nickname | dashIfEmpty}}
|
||||
</span></vn-td>
|
||||
<vn-td>
|
||||
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<a target="_blank"
|
||||
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
|
||||
<vn-icon-button
|
||||
icon="cloud_download"
|
||||
title="{{'Download file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</a>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="edit"
|
||||
ui-sref="ticket.card.dms.edit({dmsId: {{::document.dmsFk}}})"
|
||||
title="{{'Edit file' | translate}}">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="delete"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
</vn-data-viewer>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
|
|
|
@ -1,66 +1,63 @@
|
|||
<vn-crud-model
|
||||
auto-load="false"
|
||||
vn-id="model"
|
||||
url="/ticket/api/Expeditions/filter"
|
||||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
limit="20"
|
||||
data="expeditions">
|
||||
data="expeditions"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th></vn-th>
|
||||
<vn-th field="itemFk" number>Expedition</vn-th>
|
||||
<vn-th field="itemFk" number>Envialia</vn-th>
|
||||
<vn-th field="itemFk" number>Item</vn-th>
|
||||
<vn-th field="name">Name</vn-th>
|
||||
<vn-th field="isBox">Package type</vn-th>
|
||||
<vn-th field="counter" number>Counter</vn-th>
|
||||
<vn-th field="checked" number>Checked</vn-th>
|
||||
<vn-th field="worker">Worker</vn-th>
|
||||
<vn-th field="created" default-order="DESC">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="expedition in expeditions">
|
||||
<vn-td class="vn-px-md" style="width:30px;color:#FFA410;">
|
||||
<vn-icon-button icon="delete"
|
||||
ng-click="$ctrl.deleteExpedition(expedition)"
|
||||
vn-tooltip="Delete expedition">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td number>{{expedition.id | zeroFill:6}}</vn-td>
|
||||
<vn-td number>{{expedition.externalId | zeroFill:6}}</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-class="{link: expedition.itemFk}"
|
||||
ng-click="$ctrl.showItemDescriptor($event, expedition.itemFk)">
|
||||
{{expedition.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::expedition.namePackage}}</vn-td>
|
||||
<vn-td>{{::expedition.nameBox}}</vn-td>
|
||||
<vn-td number>{{::expedition.counter}}</vn-td>
|
||||
<vn-td number>{{::expedition.checked}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, expedition.workerFk)">
|
||||
{{::expedition.userNickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::expedition.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-xl">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th></vn-th>
|
||||
<vn-th field="itemFk" number>Expedition</vn-th>
|
||||
<vn-th field="itemFk" number>Envialia</vn-th>
|
||||
<vn-th field="itemFk" number>Item</vn-th>
|
||||
<vn-th field="name">Name</vn-th>
|
||||
<vn-th field="isBox">Package type</vn-th>
|
||||
<vn-th field="counter" number>Counter</vn-th>
|
||||
<vn-th field="checked" number>Checked</vn-th>
|
||||
<vn-th field="worker">Worker</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="expedition in expeditions">
|
||||
<vn-td class="vn-px-md" style="width:30px; color:#FFA410;">
|
||||
<vn-icon-button icon="delete"
|
||||
ng-click="$ctrl.deleteExpedition(expedition)"
|
||||
vn-tooltip="Delete expedition">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td number>{{expedition.id | zeroFill:6}}</vn-td>
|
||||
<vn-td number>{{expedition.externalId | zeroFill:6}}</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-class="{link: expedition.itemFk}"
|
||||
ng-click="$ctrl.showItemDescriptor($event, expedition.itemFk)">
|
||||
{{expedition.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::expedition.namePackage}}</vn-td>
|
||||
<vn-td>{{::expedition.nameBox}}</vn-td>
|
||||
<vn-td number>{{::expedition.counter}}</vn-td>
|
||||
<vn-td number>{{::expedition.checked}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, expedition.workerFk)">
|
||||
{{::expedition.userNickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::expedition.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
|
||||
</vn-vertical>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="itemDescriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
|
|
|
@ -34,7 +34,7 @@ New price: Nuevo precio
|
|||
New : Nuevo
|
||||
Next: Siguiente
|
||||
Observation type: Tipo de observación
|
||||
Original quantity: Cantidad original
|
||||
Original: Original
|
||||
Package size: Bultos
|
||||
Package type: Tipo de porte
|
||||
Phone: Teléfono
|
||||
|
@ -50,7 +50,6 @@ Shipped: F. envío
|
|||
Some fields are invalid: Algunos campos no son válidos
|
||||
State: Estado
|
||||
Tickets: Tickets
|
||||
Total import: Importe total
|
||||
Warehouse: Almacén
|
||||
Worker: Trabajador
|
||||
VAT: IVA
|
||||
|
|
|
@ -25,14 +25,16 @@
|
|||
ng-model="observation.observationTypeFk"
|
||||
data="observationTypes"
|
||||
show-field="description"
|
||||
label="Observation type" vn-one vn-focus>
|
||||
label="Observation type"
|
||||
vn-one
|
||||
vn-focus>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
class="vn-mr-lg"
|
||||
label="Description"
|
||||
ng-model="observation.description"
|
||||
rule="ticketObservation.description">
|
||||
rule="TicketObservation">
|
||||
</vn-textfield>
|
||||
<vn-auto class="vn-pt-md">
|
||||
<vn-icon-button
|
||||
|
|
|
@ -11,52 +11,49 @@
|
|||
data="packages"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-one>
|
||||
<vn-horizontal ng-repeat="package in packages track by $index">
|
||||
<vn-autocomplete vn-one
|
||||
vn-focus
|
||||
url="/ticket/api/Packagings/listPackaging"
|
||||
label="Package"
|
||||
show-field="name"
|
||||
value-field="packagingFk"
|
||||
search-function="{or: [{itemFk: $search}, {'name': {like: '%'+ $search +'%'}}]}"
|
||||
ng-model="package.packagingFk">
|
||||
<tpl-item>{{itemFk}} : {{name}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
step="1"
|
||||
label="Quantity"
|
||||
ng-model="package.quantity"
|
||||
rule="TicketPackaging.quantity">
|
||||
</vn-input-number>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Added"
|
||||
ng-model="package.created | dateTime: 'dd/MM/yyyy'"
|
||||
disabled="true"
|
||||
ng-readonly="true">
|
||||
</vn-textfield>
|
||||
<vn-auto class="vn-pt-md">
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-tooltip="Remove package"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Add package"
|
||||
vn-bind="+"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
<vn-horizontal ng-repeat="package in packages track by $index">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-focus
|
||||
url="/ticket/api/Packagings/listPackaging"
|
||||
label="Package"
|
||||
show-field="name"
|
||||
value-field="packagingFk"
|
||||
search-function="{or: [{itemFk: $search}, {'name': {like: '%'+ $search +'%'}}]}"
|
||||
ng-model="package.packagingFk">
|
||||
<tpl-item>{{itemFk}} : {{name}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
step="1"
|
||||
label="Quantity"
|
||||
ng-model="package.quantity"
|
||||
rule="TicketPackaging">
|
||||
</vn-input-number>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Added"
|
||||
ng-model="package.created"
|
||||
disabled="true"
|
||||
ng-readonly="true">
|
||||
</vn-date-picker>
|
||||
<vn-auto>
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-tooltip="Remove package"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Add package"
|
||||
vn-bind="+"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
<vn-crud-model
|
||||
auto-load="false"
|
||||
vn-id="model"
|
||||
url="/ticket/api/TicketRequests"
|
||||
fields="['id', 'description', 'created', 'requesterFk', 'atenderFk', 'quantity', 'price', 'saleFk', 'isOk']"
|
||||
order="created ASC"
|
||||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
filter="::$ctrl.filter"
|
||||
data="purchaseRequests">
|
||||
data="purchaseRequests"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="purchaseRequests"
|
||||
form="form">
|
||||
data="purchaseRequests">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-xl">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
|
@ -79,9 +77,8 @@
|
|||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
</form>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="itemDescriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
|
|
|
@ -1,54 +1,54 @@
|
|||
<vn-crud-model auto-load="false"
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/ticket/api/sales"
|
||||
filter="::$ctrl.filter"
|
||||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
limit="20"
|
||||
data="sales">
|
||||
data="sales"
|
||||
order="concept ASC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="isChecked" center>Is checked</vn-th>
|
||||
<vn-th field="itemFk" number>Item</vn-th>
|
||||
<vn-th field="concept" default-order="ASC">Description</vn-th>
|
||||
<vn-th field="quantity" number>Quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in sales">
|
||||
<vn-td center shrink>
|
||||
<vn-check
|
||||
vn-one ng-model="sale.isChecked.isChecked"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{::sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-lg">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="isChecked" center>Is checked</vn-th>
|
||||
<vn-th field="itemFk" number>Item</vn-th>
|
||||
<vn-th field="concept">Description</vn-th>
|
||||
<vn-th field="quantity" number>Quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in sales">
|
||||
<vn-td center shrink>
|
||||
<vn-check
|
||||
vn-one ng-model="sale.isChecked.isChecked"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{::sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
<vn-item-descriptor-popover vn-id="descriptor"
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
</vn-item-descriptor-popover>
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
<vn-crud-model auto-load="false"
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/ticket/api/SaleTrackings/listSaleTracking"
|
||||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
limit="20"
|
||||
data="sales">
|
||||
data="sales"
|
||||
order="itemFk DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th></vn-th>
|
||||
<vn-th field="itemFk" number default-order="DESC">Item</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th field="quantity">Quantity</vn-th>
|
||||
<vn-th field="originalQuantity">Original quantity</vn-th>
|
||||
<vn-th field="workerFk" class="ellipsize" style="max-width: 5em">Worker</vn-th>
|
||||
<vn-th field="state">State</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in sales">
|
||||
<vn-td>
|
||||
<vn-icon
|
||||
class="bright"
|
||||
icon="warning"
|
||||
ng-if="sale.quantity != sale.originalQuantity"
|
||||
vn-tooltip="The quantity do not match"></vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showItemDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td>{{::sale.quantity}}</vn-td>
|
||||
<vn-td>{{::sale.originalQuantity}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, sale.workerFk)">
|
||||
{{::sale.userNickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::sale.state}}</vn-td>
|
||||
<vn-td>{{::sale.created | dateTime: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-xl">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th field="itemFk" number>Item</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th field="quantity" number>Quantity</vn-th>
|
||||
<vn-th field="originalQuantity" number>Original</vn-th>
|
||||
<vn-th field="workerFk">Worker</vn-th>
|
||||
<vn-th field="state">State</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in sales">
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
class="bright"
|
||||
icon="warning"
|
||||
ng-if="sale.quantity != sale.originalQuantity"
|
||||
vn-tooltip="The quantity do not match">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showItemDescriptor($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::sale.quantity}}</vn-td>
|
||||
<vn-td number>{{::sale.originalQuantity}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, sale.workerFk)">
|
||||
{{::sale.userNickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::sale.state}}</vn-td>
|
||||
<vn-td>{{::sale.created | dateTime: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover vn-id="itemDescriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
</vn-item-descriptor-popover>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<vn-horizontal class="header vn-pa-md">
|
||||
<div class="header vn-pa-md">
|
||||
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
<div class="vn-pa-md">
|
||||
<vn-input-number
|
||||
vn-focus
|
||||
|
|
|
@ -64,7 +64,7 @@ class Controller {
|
|||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.clearDiscount();
|
||||
modified = false;
|
||||
this.vnTicketSale.$scope.model.refresh();
|
||||
// this.vnTicketSale.$scope.model.refresh();
|
||||
}).catch(e => {
|
||||
this.vnApp.showError(e.message);
|
||||
});
|
||||
|
@ -89,8 +89,5 @@ ngModule.component('vnTicketSaleEditDiscount', {
|
|||
mana: '<?',
|
||||
bulk: '<?',
|
||||
onHide: '&'
|
||||
},
|
||||
require: {
|
||||
vnTicketSale: '^vnTicketSale'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -190,25 +190,37 @@
|
|||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-item-descriptor-popover vn-id="descriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
</vn-item-descriptor-popover>
|
||||
</vn-vertical>
|
||||
<vn-float-button
|
||||
ng-show="$ctrl.isEditable"
|
||||
ng-click="$ctrl.newOrderFromTicket()"
|
||||
icon="add"
|
||||
vn-tooltip="Add item"
|
||||
vn-bind="+"
|
||||
fixed-bottom-right>
|
||||
</vn-float-button>
|
||||
|
||||
<!-- Edit Price Popover -->
|
||||
<vn-popover
|
||||
class="edit dialog-summary"
|
||||
vn-id="edit-price-popover"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
</vn-item-descriptor-popover>
|
||||
|
||||
<!-- Edit Price Popover -->
|
||||
<vn-popover
|
||||
class="dialog-summary"
|
||||
vn-id="edit-price-popover"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<div class="edit-price">
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.mana == null"
|
||||
style="padding: 1em;"
|
||||
enable="true">
|
||||
</vn-spinner>
|
||||
<div ng-if="$ctrl.mana != null">
|
||||
<vn-horizontal class="header vn-pa-md">
|
||||
<div class="header vn-pa-md">
|
||||
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
<div class="vn-pa-md">
|
||||
<vn-input-number
|
||||
vn-focus
|
||||
|
@ -225,14 +237,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</vn-popover>
|
||||
</div>
|
||||
</vn-popover>
|
||||
|
||||
<!-- Edit Popover -->
|
||||
<vn-popover
|
||||
class="edit dialog-summary"
|
||||
vn-id="edit-popover"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<!-- Edit Popover -->
|
||||
<vn-popover
|
||||
class="dialog-summary"
|
||||
vn-id="edit-popover"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<div class="edit-price">
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.mana == null"
|
||||
style="padding: 1em;"
|
||||
|
@ -245,141 +259,137 @@
|
|||
edit="$ctrl.edit"
|
||||
on-hide="$ctrl.hideEditPopover()">
|
||||
</vn-ticket-sale-edit-discount>
|
||||
</vn-popover>
|
||||
</div>
|
||||
</vn-popover>
|
||||
|
||||
<!-- Edit Dialog -->
|
||||
<vn-dialog
|
||||
vn-id="editDialog"
|
||||
class="edit"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<tpl-body>
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.mana == null"
|
||||
style="padding: 1em;"
|
||||
enable="true">
|
||||
</vn-spinner>
|
||||
<vn-ticket-sale-edit-discount
|
||||
ng-if="$ctrl.mana != null"
|
||||
mana="$ctrl.mana"
|
||||
bulk="true"
|
||||
edit="$ctrl.edit"
|
||||
on-hide="$ctrl.hideEditDialog()">
|
||||
</vn-ticket-sale-edit-discount>
|
||||
</tpl-body>
|
||||
</vn-dialog>
|
||||
|
||||
<!-- Transfer Popover -->
|
||||
<vn-popover class="transfer" vn-id="transfer">
|
||||
<div class="vn-pa-md">
|
||||
<!-- Transfer Popover -->
|
||||
<vn-popover vn-id="transfer">
|
||||
<div class="vn-pa-md transfer">
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<h4 translate>Sales to transfer</h4>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th number shrink>Id</vn-th>
|
||||
<vn-th>Item</vn-th>
|
||||
<vn-th number shrink>Quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in $ctrl.transfer.sales">
|
||||
<vn-td number shrink>{{::sale.itemFk | zeroFill:6}}</vn-td>
|
||||
<vn-td>
|
||||
<span title="{{::sale.concept}}">{{::sale.concept}}</span>
|
||||
</vn-td>
|
||||
<vn-td-editable number shrink>
|
||||
<text>{{sale.quantity}}</text>
|
||||
<field>
|
||||
<vn-input-number
|
||||
vn-focus
|
||||
ng-model="sale.quantity">
|
||||
</vn-input-number>
|
||||
</field>
|
||||
</vn-td-editable>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<h4 translate>Sales to transfer</h4>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th number shrink>Id</vn-th>
|
||||
<vn-th>Item</vn-th>
|
||||
<vn-th number shrink>Quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in $ctrl.transfer.sales">
|
||||
<vn-td number shrink>{{::sale.itemFk | zeroFill:6}}</vn-td>
|
||||
<vn-td>
|
||||
<span title="{{::sale.concept}}">{{::sale.concept}}</span>
|
||||
</vn-td>
|
||||
<vn-td-editable number shrink>
|
||||
<text>{{sale.quantity}}</text>
|
||||
<field>
|
||||
<vn-input-number
|
||||
vn-focus
|
||||
ng-model="sale.quantity">
|
||||
</vn-input-number>
|
||||
</field>
|
||||
</vn-td-editable>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-horizontal>
|
||||
<h4 vn-one translate>Destination ticket</h4>
|
||||
<vn-icon vn-none
|
||||
color-secondary
|
||||
vn-tooltip="You have to allow pop-ups in your web browser to use this functionality"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</vn-horizontal>
|
||||
<table class="vn-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number>ID</th>
|
||||
<th number>F. envio</th>
|
||||
<th number>Agencia</th>
|
||||
<th number>Almacen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-if="$ctrl.transfer.lastActiveTickets.length === 0" >
|
||||
<td colspan="4" style="text-align: center" translate>No results</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="clickable"
|
||||
ng-repeat="ticket in $ctrl.transfer.lastActiveTickets track by ticket.id"
|
||||
ng-click="$ctrl.transferSales(ticket.id)">
|
||||
<td number>{{::ticket.id}}</td>
|
||||
<td number>{{::ticket.shipped | dateTime: 'dd/MM/yyyy'}}</td>
|
||||
<td number>{{::ticket.agencyName}}</td>
|
||||
<td number>{{::ticket.warehouseName}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<vn-horizontal class="vn-py-md">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Transfer to ticket"
|
||||
ng-model="$ctrl.transfer.ticketId"
|
||||
type="number">
|
||||
</vn-textfield>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
icon="arrow_forward_ios"
|
||||
ng-click="$ctrl.transferSales($ctrl.transfer.ticketId)">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-py-md">
|
||||
<vn-button
|
||||
label="New ticket"
|
||||
ng-click="$ctrl.transferSales()">
|
||||
</vn-button>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<h4 vn-one translate>Destination ticket</h4>
|
||||
<vn-icon vn-none
|
||||
color-secondary
|
||||
vn-tooltip="You have to allow pop-ups in your web browser to use this functionality"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
</vn-popover>
|
||||
<table class="vn-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number>Id</th>
|
||||
<th number>F. envio</th>
|
||||
<th number>Agencia</th>
|
||||
<th number>Almacen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-if="$ctrl.transfer.lastActiveTickets.length === 0" >
|
||||
<td colspan="4" style="text-align: center" translate>No results</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="clickable"
|
||||
ng-repeat="ticket in $ctrl.transfer.lastActiveTickets track by ticket.id"
|
||||
ng-click="$ctrl.transferSales(ticket.id)">
|
||||
<td number>{{::ticket.id}}</td>
|
||||
<td number>{{::ticket.shipped | dateTime: 'dd/MM/yyyy'}}</td>
|
||||
<td number>{{::ticket.agencyName}}</td>
|
||||
<td number>{{::ticket.warehouseName}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<vn-horizontal class="vn-py-md">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Transfer to ticket"
|
||||
ng-model="$ctrl.transfer.ticketId"
|
||||
type="number">
|
||||
</vn-textfield>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
icon="arrow_forward_ios"
|
||||
ng-click="$ctrl.transferSales($ctrl.transfer.ticketId)">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-py-md">
|
||||
<vn-button
|
||||
label="New ticket"
|
||||
ng-click="$ctrl.transferSales()">
|
||||
</vn-button>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
</vn-popover>
|
||||
|
||||
<!-- Edit Dialog -->
|
||||
<vn-dialog
|
||||
vn-id="editDialog"
|
||||
class="edit"
|
||||
on-open="$ctrl.getManaSalespersonMana()"
|
||||
on-close="$ctrl.mana = null">
|
||||
<tpl-body>
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.mana == null"
|
||||
style="padding: 1em;"
|
||||
enable="true">
|
||||
</vn-spinner>
|
||||
<vn-ticket-sale-edit-discount
|
||||
ng-if="$ctrl.mana != null"
|
||||
mana="$ctrl.mana"
|
||||
bulk="true"
|
||||
edit="$ctrl.edit"
|
||||
on-hide="$ctrl.hideEditDialog()">
|
||||
</vn-ticket-sale-edit-discount>
|
||||
</tpl-body>
|
||||
</vn-dialog>
|
||||
|
||||
<!-- SMS Dialog -->
|
||||
<vn-client-sms
|
||||
vn-id="sms"
|
||||
sms="$ctrl.newSMS">
|
||||
</vn-client-sms>
|
||||
|
||||
<!-- SMS Dialog -->
|
||||
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
|
||||
<!-- SMS Dialog -->
|
||||
</vn-vertical>
|
||||
<vn-confirm
|
||||
vn-id="delete-lines"
|
||||
question="You are going to delete lines of the ticket"
|
||||
message="Continue anyway?"
|
||||
on-response="$ctrl.onRemoveLinesClick(response)">
|
||||
</vn-confirm>
|
||||
|
||||
<vn-confirm
|
||||
vn-id="delete-ticket"
|
||||
question="Do you want to delete it?"
|
||||
message="This ticket is now empty"
|
||||
on-response="$ctrl.transferSales($ctrl.transfer.ticketId, response)">
|
||||
</vn-confirm>
|
||||
<vn-float-button
|
||||
ng-show="$ctrl.isEditable"
|
||||
ng-click="$ctrl.newOrderFromTicket()"
|
||||
icon="add"
|
||||
vn-tooltip="Add item"
|
||||
vn-bind="+"
|
||||
fixed-bottom-right>
|
||||
</vn-float-button>
|
||||
</vn-confirm>
|
|
@ -5,34 +5,34 @@ vn-ticket-sale {
|
|||
justify-content: space-between !important;
|
||||
align-items: center;
|
||||
}
|
||||
vn-popover.edit {
|
||||
div.popover {
|
||||
width: 200px;
|
||||
|
||||
vn-ticket-sale {
|
||||
tr .mdl-textfield{
|
||||
width: inherit;
|
||||
max-width: 100%;
|
||||
}
|
||||
vn-horizontal.header {
|
||||
background-color: $color-main;
|
||||
color: $color-font-dark;
|
||||
}
|
||||
vn-table {
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
.taxes {
|
||||
max-width: 10em;
|
||||
border: $border-thin-light;
|
||||
text-align: right;
|
||||
padding: .5em !important;
|
||||
|
||||
h5 {
|
||||
color: inherit;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
p.simulatorTitle {
|
||||
margin-bottom: 0px;
|
||||
font-size: 12px;
|
||||
color: $color-main;
|
||||
}
|
||||
vn-label-value {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
div.simulator{
|
||||
text-align: center;
|
||||
& > p {
|
||||
font-size: 1.2em;
|
||||
margin: .2em;
|
||||
}
|
||||
}
|
||||
vn-dialog.edit {
|
||||
@extend vn-popover.edit;
|
||||
|
||||
@extend .edit-price;
|
||||
|
||||
&>div{
|
||||
padding: 0!important;
|
||||
}
|
||||
|
@ -52,71 +52,63 @@ vn-ticket-sale {
|
|||
padding-bottom: 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
vn-ticket-sale{
|
||||
tr .mdl-textfield{
|
||||
width: inherit;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
vn-popover.transfer{
|
||||
vn-textfield {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
vn-horizontal {
|
||||
& > vn-one:nth-child(1){
|
||||
border-right: 1px solid $color-bg;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
& > vn-one:nth-child(2){
|
||||
margin-left: 1em
|
||||
}
|
||||
}
|
||||
vn-table, table {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
vn-table {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: 25em;
|
||||
width: 30em;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 25em
|
||||
}
|
||||
}
|
||||
|
||||
vn-dialog.ticket-create{
|
||||
vn-button[label=Cancel]{
|
||||
vn-dialog.ticket-create {
|
||||
vn-button[label=Cancel] {
|
||||
display: none;
|
||||
}
|
||||
vn-card.vn-ticket-create {
|
||||
padding: 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
vn-table {
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
.vn-popover .transfer {
|
||||
vn-textfield {
|
||||
margin: 0
|
||||
}
|
||||
vn-horizontal {
|
||||
& > vn-one:nth-child(1) {
|
||||
border-right: 1px solid $color-bg;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
& > vn-one:nth-child(2) {
|
||||
margin-left: 1em
|
||||
}
|
||||
}
|
||||
.taxes {
|
||||
max-width: 10em;
|
||||
border: $border-thin-light;
|
||||
text-align: right;
|
||||
padding: .5em !important;
|
||||
vn-table, table {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
vn-table {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: 25em;
|
||||
width: 30em;
|
||||
}
|
||||
table {
|
||||
width: 25em
|
||||
}
|
||||
}
|
||||
.edit-price {
|
||||
width: 200px;
|
||||
|
||||
.header {
|
||||
background-color: $color-main;
|
||||
color: $color-font-dark;
|
||||
|
||||
& > p {
|
||||
font-size: 1.2em;
|
||||
margin: .2em;
|
||||
h5 {
|
||||
color: inherit;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
p.simulatorTitle {
|
||||
margin-bottom: 0px;
|
||||
font-size: 12px;
|
||||
color: $color-main;
|
||||
}
|
||||
vn-label-value {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
div.simulator {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -9,64 +9,61 @@
|
|||
vn-id="watcher"
|
||||
data="$ctrl.services">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-one>
|
||||
<vn-horizontal ng-repeat="service in $ctrl.services track by $index">
|
||||
<vn-autocomplete vn-one
|
||||
vn-focus
|
||||
url="/api/TicketServiceTypes"
|
||||
label="Description"
|
||||
show-field="name"
|
||||
value-field="name"
|
||||
ng-model="service.description">
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
vn-auto
|
||||
class="vn-my-md"
|
||||
icon="add_circle"
|
||||
vn-tooltip="New service type"
|
||||
ng-click="$ctrl.newServiceTypeDialog($index)"
|
||||
vn-acl="administrative">
|
||||
</vn-icon-button>
|
||||
<vn-input-number
|
||||
vn-one min="0"
|
||||
step="1"
|
||||
label="Quantity"
|
||||
ng-model="service.quantity"
|
||||
rule="TicketService.quantity">
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
label="Price"
|
||||
ng-model="service.price"
|
||||
step="0.01">
|
||||
</vn-input-number>
|
||||
<vn-autocomplete vn-one
|
||||
url="/api/TaxClasses"
|
||||
label="Tax class"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
ng-model="service.taxClassFk">
|
||||
</vn-autocomplete>
|
||||
<vn-auto class="vn-pt-md">
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-tooltip="Remove service"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-horizontal ng-repeat="service in $ctrl.services track by $index">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-focus
|
||||
url="/api/TicketServiceTypes"
|
||||
label="Description"
|
||||
show-field="name"
|
||||
value-field="name"
|
||||
ng-model="service.description">
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Add service"
|
||||
vn-bind="+"
|
||||
vn-auto
|
||||
class="vn-my-md"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
vn-tooltip="New service type"
|
||||
ng-click="$ctrl.newServiceTypeDialog($index)"
|
||||
vn-acl="administrative">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
<vn-input-number
|
||||
vn-one min="0"
|
||||
step="1"
|
||||
label="Quantity"
|
||||
ng-model="service.quantity"
|
||||
rule="TicketService">
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
label="Price"
|
||||
ng-model="service.price"
|
||||
step="0.01">
|
||||
</vn-input-number>
|
||||
<vn-autocomplete vn-one
|
||||
url="/api/TaxClasses"
|
||||
label="Tax class"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
ng-model="service.taxClassFk">
|
||||
</vn-autocomplete>
|
||||
<vn-auto>
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-tooltip="Remove service"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Add service"
|
||||
vn-bind="+"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
|
|
|
@ -41,8 +41,7 @@ class Controller {
|
|||
}
|
||||
|
||||
onNewServiceTypeOpen() {
|
||||
this.newServiceType.name = '';
|
||||
|
||||
this.newServiceType = {};
|
||||
this.nameInput = this.$element[0].querySelector('.edit input');
|
||||
this.nameInput.focus();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import './index.js';
|
||||
import UserError from 'core/lib/user-error';
|
||||
|
||||
describe('Ticket component vnTicketService', () => {
|
||||
fdescribe('Ticket component vnTicketService', () => {
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
|
@ -63,7 +62,6 @@ describe('Ticket component vnTicketService', () => {
|
|||
controller.currentServiceIndex = 0;
|
||||
|
||||
$httpBackend.when('POST', '/api/TicketServiceTypes').respond({id: 4001, name: 'great service!'});
|
||||
$httpBackend.expect('POST', '/api/TicketServiceTypes');
|
||||
controller.onNewServiceTypeResponse('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
</vn-one>
|
||||
<vn-auto name="sales">
|
||||
<h4 translate>Sale</h4>
|
||||
<vn-table class="vn-grid">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink></vn-th>
|
||||
|
@ -108,7 +108,8 @@
|
|||
max-length="6"
|
||||
item="::sale.item"
|
||||
name="::sale.concept"
|
||||
sub-name="::sale.item.subName"/>
|
||||
sub-name="::sale.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::sale.price | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td number>{{::sale.discount}} %</vn-td>
|
||||
|
|
|
@ -1,41 +1,39 @@
|
|||
<vn-crud-model auto-load="false"
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/ticket/api/TicketTrackings"
|
||||
filter="::$ctrl.filter"
|
||||
link="{ticketFk: $ctrl.$stateParams.id}"
|
||||
limit="20"
|
||||
data="trackings">
|
||||
data="trackings"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-vertical compact>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-title>Tracking</vn-title>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="state">State</vn-th>
|
||||
<vn-th field="worker">Worker</vn-th>
|
||||
<vn-th field="created" default-order="DESC">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="tracking in trackings">
|
||||
<vn-td>{{::tracking.state.name}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, tracking.worker.user.id)">
|
||||
{{::tracking.worker.user.nickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::tracking.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-md">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="state">State</vn-th>
|
||||
<vn-th field="worker">Worker</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="tracking in trackings">
|
||||
<vn-td>{{::tracking.state.name}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, tracking.worker.user.id)">
|
||||
{{::tracking.worker.user.nickname | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::tracking.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
</vn-data-viewer>
|
||||
<a ui-sref="ticket.card.tracking.edit" vn-bind="+" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
|
|
|
@ -1,88 +1,90 @@
|
|||
<vn-crud-model auto-load="false"
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/ticket/api/TicketWeeklies/filter"
|
||||
filter="::$ctrl.filter"
|
||||
limit="20"
|
||||
data="weeklies"
|
||||
order="ticketFk"
|
||||
primary-key="ticketFk">
|
||||
primary-key="ticketFk"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<div class="content-block">
|
||||
<div class="vn-list">
|
||||
<vn-card class="vn-px-md">
|
||||
<vn-horizontal>
|
||||
<vn-searchbar
|
||||
vn-id="turnSearchbar"
|
||||
style="width: 100%"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search weekly ticket by id or client id"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
<vn-card class="vn-px-md vn-w-sm">
|
||||
<vn-searchbar
|
||||
vn-id="turnSearchbar"
|
||||
style="width: 100%"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
info="Search weekly ticket by id or client id"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-md vn-my-md vn-mb-xl">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="ticketFk" number>Ticket ID</vn-th>
|
||||
<vn-th field="weekDay">Client</vn-th>
|
||||
<vn-th>Weekday</vn-th>
|
||||
<vn-th>Warehouse</vn-th>
|
||||
<vn-th>Salesperson</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="weekly in weeklies" class="clickable" ui-sref="ticket.card.summary({id: {{::weekly.ticketFk}}})">
|
||||
<vn-td number>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showTicketDescriptor($event, weekly.ticketFk)">
|
||||
{{weekly.ticketFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showClientDescriptor($event, weekly.clientFk)"
|
||||
title ="{{::weekly.clientName}}">
|
||||
{{::weekly.clientName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td ng-click="$ctrl.preventNavigation($event)">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-id="weekday"
|
||||
ng-model="weekly.weekDay"
|
||||
data="$ctrl.weekdays"
|
||||
show-field="name"
|
||||
translate-fields="['name']"
|
||||
value-field="id"
|
||||
on-change="$ctrl.onWeekdayUpdate(weekly.ticketFk, weekday.selection.id)"
|
||||
order="id"
|
||||
class="dense">
|
||||
</vn-autocomplete>
|
||||
</vn-td>
|
||||
<vn-td>{{::weekly.warehouseName}}</vn-td>
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, weekly.workerFk)">
|
||||
{{::weekly.nickName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="delete"
|
||||
ng-click="$ctrl.deleteWeekly($index)"
|
||||
vn-tooltip="Delete">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</div>
|
||||
<div class="vn-ma-md">
|
||||
<vn-card class="vn-my-md vn-pa-md compact">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="ticketFk" number>Ticket ID</vn-th>
|
||||
<vn-th field="weekDay">Client</vn-th>
|
||||
<vn-th>Weekday</vn-th>
|
||||
<vn-th>Warehouse</vn-th>
|
||||
<vn-th>Salesperson</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="weekly in weeklies" class="clickable" ui-sref="ticket.card.summary({id: {{::weekly.ticketFk}}})">
|
||||
<vn-td number>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showTicketDescriptor($event, weekly.ticketFk)">
|
||||
{{weekly.ticketFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showClientDescriptor($event, weekly.clientFk)"
|
||||
title ="{{::weekly.clientName}}">
|
||||
{{::weekly.clientName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td ng-click="$ctrl.preventNavigation($event)">
|
||||
<vn-autocomplete vn-one
|
||||
vn-id="weekday"
|
||||
ng-model="weekly.weekDay"
|
||||
data="$ctrl.weekdays"
|
||||
show-field="name"
|
||||
translate-fields="['name']"
|
||||
value-field="id"
|
||||
on-change="$ctrl.onWeekdayUpdate(weekly.ticketFk, weekday.selection.id)"
|
||||
order="id">
|
||||
</vn-autocomplete>
|
||||
</vn-td>
|
||||
<vn-td>{{::weekly.warehouseName}}</vn-td>
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, weekly.workerFk)">
|
||||
{{::weekly.nickName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="delete"
|
||||
ng-click="$ctrl.deleteWeekly($index)"
|
||||
vn-tooltip="Delete">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
</div>
|
||||
</vn-data-viewer>
|
||||
</div>
|
||||
<vn-client-descriptor-popover vn-id="clientDescriptor"></vn-client-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticketDescriptor">
|
||||
</vn-ticket-descriptor-popover>
|
||||
|
@ -95,6 +97,9 @@
|
|||
question="This ticket will be removed from weekly tickets! Continue anyway?"
|
||||
message="You are going to delete this weekly ticket">
|
||||
</vn-confirm>
|
||||
<a ui-sref="ticket.weekly.create" vn-tooltip="Add weekly ticket" vn-bind="+" fixed-bottom-right>
|
||||
<a ui-sref="ticket.weekly.create"
|
||||
vn-tooltip="Add weekly ticket"
|
||||
vn-bind="+"
|
||||
fixed-bottom-right>
|
||||
<vn-float-button icon="person_add"></vn-float-button>
|
||||
</a>
|
Loading…
Reference in New Issue