Merge pull request '1882-descriptorRefactor' (#250) from 1882-descriptorRefactor into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
1892447b60
|
@ -31,6 +31,7 @@ rules:
|
|||
curly: [error, multi-or-nest]
|
||||
indent: [error, 4]
|
||||
arrow-parens: [error, as-needed]
|
||||
jasmine/no-focused-tests: 0
|
||||
no-multiple-empty-lines: ["error", { "max": 1, "maxEOF": 1 }]
|
||||
space-in-parens: ["error", "never"]
|
||||
space-in-parens: ["error", "never"]
|
||||
jasmine/no-focused-tests: 0
|
||||
jasmine/prefer-toHaveBeenCalledWith: 0
|
|
@ -5,11 +5,11 @@ export default {
|
|||
userMenuButton: '#user',
|
||||
logoutButton: '#logout',
|
||||
applicationsMenuVisible: '.modules-menu',
|
||||
clientsButton: '.modules-menu > li[ui-sref="client.index"]',
|
||||
itemsButton: '.modules-menu > li[ui-sref="item.index"]',
|
||||
ticketsButton: '.modules-menu > li[ui-sref="ticket.index"]',
|
||||
invoiceOutButton: '.modules-menu > li[ui-sref="invoiceOut.index"]',
|
||||
claimsButton: '.modules-menu > li[ui-sref="claim.index"]',
|
||||
clientsButton: '.modules-menu [ui-sref="client.index"]',
|
||||
itemsButton: '.modules-menu [ui-sref="item.index"]',
|
||||
ticketsButton: '.modules-menu [ui-sref="ticket.index"]',
|
||||
invoiceOutButton: '.modules-menu [ui-sref="invoiceOut.index"]',
|
||||
claimsButton: '.modules-menu [ui-sref="claim.index"]',
|
||||
returnToModuleIndexButton: 'a[ui-sref="order.index"]',
|
||||
homeButton: 'vn-topbar > div.side.start > a',
|
||||
userLocalWarehouse: '.user-popover vn-autocomplete[ng-model="$ctrl.localWarehouseFk"]',
|
||||
|
@ -56,8 +56,8 @@ export default {
|
|||
cancelButton: 'vn-button[href="#!/client/index"]'
|
||||
},
|
||||
clientDescriptor: {
|
||||
moreMenu: 'vn-client-descriptor vn-icon-menu[icon=more_vert]',
|
||||
simpleTicketButton: '.vn-drop-down.shown li[name="Simple ticket"]'
|
||||
moreMenu: 'vn-client-descriptor vn-icon-button[icon=more_vert]',
|
||||
simpleTicketButton: '.vn-menu [name="simpleTicket"]'
|
||||
},
|
||||
clientBasicData: {
|
||||
basicDataButton: 'vn-left-menu a[ui-sref="client.card.basicData"]',
|
||||
|
@ -241,14 +241,14 @@ export default {
|
|||
},
|
||||
itemDescriptor: {
|
||||
goBackToModuleIndexButton: 'vn-item-descriptor a[href="#!/item/index"]',
|
||||
moreMenu: 'vn-item-descriptor vn-icon-menu[icon=more_vert]',
|
||||
moreMenuRegularizeButton: '.vn-drop-down.shown li[name="Regularize stock"]',
|
||||
moreMenu: 'vn-item-descriptor vn-icon-button[icon=more_vert]',
|
||||
moreMenuRegularizeButton: '.vn-menu [name="regularizeStock"]',
|
||||
regularizeQuantity: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.quantity"]',
|
||||
regularizeWarehouse: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
|
||||
editButton: 'vn-item-descriptor vn-float-button[icon="edit"]',
|
||||
regularizeSaveButton: '.vn-dialog.shown tpl-buttons > button',
|
||||
inactiveIcon: 'vn-item-descriptor vn-icon[icon="icon-unavailable"]',
|
||||
navigateBackToIndex: 'vn-item-descriptor vn-icon[icon="chevron_left"]'
|
||||
navigateBackToIndex: 'vn-item-descriptor [name="goToModuleIndex"]'
|
||||
},
|
||||
itemRequest: {
|
||||
firstRequestItemID: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(7)',
|
||||
|
@ -378,7 +378,7 @@ export default {
|
|||
topbarSearch: 'vn-searchbar',
|
||||
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
|
||||
searchButton: 'vn-searchbar vn-icon[icon="search"]',
|
||||
moreMenu: 'vn-ticket-index vn-icon-menu[icon=more_vert]',
|
||||
moreMenu: 'vn-ticket-index vn-icon-button[icon=more_vert]',
|
||||
sixthWeeklyTicket: 'vn-ticket-weekly-index vn-table vn-tr:nth-child(6)',
|
||||
weeklyTicket: 'vn-ticket-weekly-index vn-table > div > vn-tbody > vn-tr',
|
||||
firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
|
@ -397,13 +397,13 @@ export default {
|
|||
idLabelValue: 'vn-ticket-descriptor vn-label-value[label="Id"]',
|
||||
stateLabelValue: 'vn-ticket-descriptor vn-label-value[label="State"]',
|
||||
goBackToModuleIndexButton: 'vn-ticket-descriptor a[ui-sref="ticket.index"]',
|
||||
moreMenu: 'vn-ticket-descriptor vn-icon-menu[icon=more_vert]',
|
||||
moreMenuAddStowaway: '.vn-drop-down.shown li[name="Add stowaway"]',
|
||||
moreMenuDeleteStowawayButton: '.vn-drop-down.shown li[name="Delete stowaway"]',
|
||||
moreMenuAddToTurn: '.vn-drop-down.shown li[name="Add turn"]',
|
||||
moreMenuDeleteTicket: '.vn-drop-down.shown li[name="Delete ticket"]',
|
||||
moreMenuMakeInvoice: '.vn-drop-down.shown li[name="Make invoice"]',
|
||||
moreMenuChangeShippedHour: '.vn-drop-down.shown li[name="Change shipped hour"]',
|
||||
moreMenu: 'vn-ticket-descriptor vn-icon-button[icon=more_vert]',
|
||||
moreMenuAddStowaway: '.vn-menu [name="addStowaway"]',
|
||||
moreMenuDeleteStowawayButton: '.vn-menu [name="deleteStowaway"]',
|
||||
moreMenuAddToTurn: '.vn-menu [name="addTurn"]',
|
||||
moreMenuDeleteTicket: '.vn-menu [name="deleteTicket"]',
|
||||
moreMenuMakeInvoice: '.vn-menu [name="makeInvoice"]',
|
||||
moreMenuChangeShippedHour: '.vn-menu [name="changeShipped"]',
|
||||
changeShippedHourDialog: '.vn-dialog.shown',
|
||||
changeShippedHour: '.vn-dialog.shown vn-input-time[ng-model="$ctrl.newShipped"]',
|
||||
addStowawayDialogFirstTicket: '.vn-dialog.shown vn-table vn-tbody vn-tr',
|
||||
|
@ -412,7 +412,7 @@ export default {
|
|||
saturdayButton: '.vn-popup.shown vn-tool-bar > vn-button:nth-child(6)',
|
||||
acceptDeleteButton: '.vn-dialog.shown button[response="accept"]',
|
||||
acceptChangeHourButton: '.vn-dialog.shown button[response="accept"]',
|
||||
descriptorDeliveryDate: 'vn-ticket-descriptor > div > div.body > div.attributes > vn-label-value:nth-child(6) > section > span',
|
||||
descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(3) > section > span',
|
||||
acceptInvoiceOutButton: '.vn-confirm.shown button[response="accept"]',
|
||||
acceptDeleteStowawayButton: '.vn-dialog.shown button[response="accept"]'
|
||||
},
|
||||
|
@ -442,9 +442,9 @@ export default {
|
|||
saleLine: 'vn-table div > vn-tbody > vn-tr',
|
||||
saleDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
||||
saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.item.id})"]',
|
||||
descriptorItemDiaryButton: 'vn-item-descriptor .quicklinks.ng-scope > vn-horizontal > a > vn-icon > i',
|
||||
descriptorItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
||||
newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]',
|
||||
newItemButton: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-one > vn-icon-button > button > vn-icon > i',
|
||||
newItemButton: 'vn-ticket-sale vn-card vn-icon-button[icon="add_circle"]',
|
||||
moreMenu: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] > div > button',
|
||||
moreMenuCreateClaim: '.vn-drop-down.shown li[name="Add claim"]',
|
||||
moreMenuReserve: '.vn-drop-down.shown li[name="Mark as reserved"]',
|
||||
|
@ -479,8 +479,8 @@ export default {
|
|||
secondSaleIdInput: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
|
||||
secondSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
|
||||
secondSaleQuantity: 'vn-ticket-sale vn-table vn-tr:nth-child(2) vn-input-number',
|
||||
secondSaleConceptCell: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(6)',
|
||||
secondSaleConceptInput: 'vn-ticket-sale vn-table vn-tr:nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield',
|
||||
secondSaleConceptCell: 'vn-ticket-sale vn-tbody > :nth-child(2) > :nth-child(6)',
|
||||
secondSaleConceptInput: 'vn-ticket-sale vn-tbody > :nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield',
|
||||
totalImport: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
|
||||
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
|
||||
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
|
||||
|
@ -558,8 +558,8 @@ export default {
|
|||
searchButton: 'vn-searchbar vn-icon[icon="search"]'
|
||||
},
|
||||
claimDescriptor: {
|
||||
moreMenu: 'vn-claim-descriptor vn-icon-menu[icon=more_vert]',
|
||||
moreMenuDeleteClaim: '.vn-drop-down.shown li[name="Delete claim"]',
|
||||
moreMenu: 'vn-claim-descriptor vn-icon-button[icon=more_vert]',
|
||||
moreMenuDeleteClaim: '.vn-menu [name="deleteClaim"]',
|
||||
acceptDeleteClaim: '.vn-confirm.shown button[response="accept"]'
|
||||
},
|
||||
claimSummary: {
|
||||
|
@ -569,9 +569,9 @@ export default {
|
|||
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',
|
||||
itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]',
|
||||
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor vn-quick-links > a[href="#!/client/21/summary"]',
|
||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
|
||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
||||
},
|
||||
|
@ -787,7 +787,7 @@ export default {
|
|||
weekWorkedHours: 'vn-worker-time-control vn-side-menu vn-label-value > section > span',
|
||||
nextMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_right]',
|
||||
secondWeekDay: 'vn-worker-time-control vn-side-menu vn-calendar .day:nth-child(8) > .day-number',
|
||||
navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]',
|
||||
navigateBackToIndex: 'vn-worker-descriptor [name="goToModuleIndex"]',
|
||||
acceptDeleteDialog: '.vn-confirm.shown button[response="accept"]'
|
||||
},
|
||||
invoiceOutIndex: {
|
||||
|
@ -796,10 +796,10 @@ export default {
|
|||
searchResult: 'vn-invoice-out-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
},
|
||||
invoiceOutDescriptor: {
|
||||
moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[icon=more_vert]',
|
||||
moreMenuDeleteInvoiceOut: '.vn-drop-down.shown li[name="Delete Invoice"]',
|
||||
moreMenuBookInvoiceOut: '.vn-drop-down.shown li[name="Book invoice"]',
|
||||
moreMenuShowInvoiceOutPdf: '.vn-drop-down.shown li[name="Show invoice PDF"]',
|
||||
moreMenu: 'vn-invoice-out-descriptor vn-icon-button[icon=more_vert]',
|
||||
moreMenuDeleteInvoiceOut: '.vn-menu [name="deleteInvoice"]',
|
||||
moreMenuBookInvoiceOut: '.vn-menu [name="bookInvoice"]',
|
||||
moreMenuShowInvoiceOutPdf: '.vn-menu [name="showInvoicePdf"]',
|
||||
acceptDeleteButton: '.vn-confirm.shown button[response="accept"]',
|
||||
acceptBookingButton: '.vn-confirm.shown button[response="accept"]'
|
||||
},
|
||||
|
@ -851,8 +851,8 @@ export default {
|
|||
confirmed: 'vn-entry-summary vn-check[label="Confirmed"]',
|
||||
},
|
||||
entryDescriptor: {
|
||||
agency: 'vn-entry-descriptor div.body vn-label-value:nth-child(3) span',
|
||||
travelsQuicklink: 'vn-entry-descriptor vn-quick-links > a:nth-child(1)',
|
||||
entriesQuicklink: 'vn-entry-descriptor vn-quick-links > a:nth-child(2)'
|
||||
agency: 'vn-entry-descriptor div.body vn-label-value:nth-child(2) span',
|
||||
travelsQuicklink: 'vn-entry-descriptor vn-quick-link[icon="local_airport"] > a',
|
||||
entriesQuicklink: 'vn-entry-descriptor vn-quick-link[icon="icon-entry"] > a'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
<div class="fix suffix"></div>
|
||||
<label>
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate>{{$ctrl.label}}</span>
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
<div>
|
||||
<tpl-body>
|
||||
<h6 translate>{{::$ctrl.message}}</h6>
|
||||
<span translate>{{::$ctrl.question}}</span>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<button response="cancel" translate>Cancel</button>
|
||||
<button response="accept" translate vn-focus>Accept</button>
|
||||
</tpl-buttons>
|
||||
</div>
|
||||
<tpl-body translate>
|
||||
{{::$ctrl.question}}
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<button response="cancel" translate>Cancel</button>
|
||||
<button response="accept" translate vn-focus>Accept</button>
|
||||
</tpl-buttons>
|
|
@ -1,20 +1,13 @@
|
|||
import ngModule from '../../module';
|
||||
import Dialog from '../dialog';
|
||||
import template from './confirm.html';
|
||||
import './style.scss';
|
||||
|
||||
export default class Confirm extends Dialog {
|
||||
constructor($element, $, $transclude) {
|
||||
super($element, $, $transclude);
|
||||
this.fillSlots(template);
|
||||
}
|
||||
}
|
||||
export default class Confirm extends Dialog {}
|
||||
|
||||
ngModule.vnComponent('vnConfirm', {
|
||||
slotTemplate: require('./confirm.html'),
|
||||
controller: Confirm,
|
||||
transclude: true,
|
||||
bindings: {
|
||||
question: '@',
|
||||
message: '@?'
|
||||
question: '@'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Floating box displaying debugging information.
|
||||
* Enabled only in development environment.
|
||||
*/
|
||||
export default class Controller {
|
||||
export default class Controller extends Component {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.env = process.env.NODE_ENV || 'development';
|
||||
|
||||
if (this.env == 'development')
|
||||
this.interval = setInterval(() => $.$digest(), 2000);
|
||||
else
|
||||
$element[0].style.display = 'none';
|
||||
|
||||
$element[0].addEventListener('mouseover',
|
||||
() => this.classList.toggle('right'));
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.component('vnDebugInfo', {
|
||||
ngModule.vnComponent('vnDebugInfo', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "variables";
|
||||
|
||||
vn-debug-info {
|
||||
.vn-debug-info {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
|
@ -13,8 +13,9 @@ vn-debug-info {
|
|||
box-shadow: $shadow;
|
||||
transition: opacity 400ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
opacity: .5;
|
||||
&.right {
|
||||
left: auto;
|
||||
right: 16px;
|
||||
}
|
||||
& > h6 {
|
||||
font-weight: normal;
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
<div
|
||||
ng-if="$ctrl.loading"
|
||||
class="loading-overlap shown">
|
||||
<vn-spinner enable="true"></vn-spinner>
|
||||
</div>
|
||||
<vn-button
|
||||
ng-click="$ctrl.hide()"
|
||||
translate-attr="{title: 'Close'}"
|
||||
icon="clear"
|
||||
class="flat close">
|
||||
</vn-button>
|
||||
<form>
|
||||
<default>
|
||||
<div
|
||||
class="body"
|
||||
ng-transclude="body">
|
||||
ng-if="$ctrl.loading"
|
||||
class="loading-overlap shown">
|
||||
<vn-spinner enable="true"></vn-spinner>
|
||||
</div>
|
||||
<div
|
||||
class="buttons"
|
||||
ng-click="$ctrl.onButtonClick($event)"
|
||||
ng-transclude="buttons">
|
||||
</div>
|
||||
</form>
|
||||
<vn-button
|
||||
ng-click="$ctrl.hide()"
|
||||
translate-attr="{title: 'Close'}"
|
||||
icon="clear"
|
||||
class="flat close">
|
||||
</vn-button>
|
||||
<form>
|
||||
<h6
|
||||
ng-if="::$ctrl.message || $ctrl.$transclude.isSlotFilled('title')"
|
||||
ng-transclude="title">
|
||||
<tpl-title translate>
|
||||
{{$ctrl.message}}
|
||||
</tpl-title>
|
||||
</h6>
|
||||
<div
|
||||
class="body"
|
||||
ng-transclude="body">
|
||||
</div>
|
||||
<div
|
||||
class="buttons"
|
||||
ng-click="$ctrl.onButtonClick($event)"
|
||||
ng-transclude="buttons">
|
||||
</div>
|
||||
</form>
|
||||
</default>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import ngModule from '../../module';
|
||||
import Popup from '../popup';
|
||||
import template from './index.html';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
|
@ -16,22 +15,6 @@ import './style.scss';
|
|||
* @slot buttons The dialog HTML buttons
|
||||
*/
|
||||
export default class Dialog extends Popup {
|
||||
constructor($element, $, $transclude) {
|
||||
super($element, $, $transclude);
|
||||
this.fillDefaultSlot(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the dialog slots, it is intended to be used by child classes.
|
||||
*
|
||||
* @param {String} template The HTML template string
|
||||
*/
|
||||
fillSlots(template) {
|
||||
let $template = angular.element(template);
|
||||
this.fillSlot('body', $template.find('tpl-body'));
|
||||
this.fillSlot('buttons', $template.find('tpl-buttons'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the dialog and optionally registers a handler for the response.
|
||||
*
|
||||
|
@ -149,12 +132,15 @@ export default class Dialog extends Popup {
|
|||
}
|
||||
|
||||
ngModule.vnComponent('vnDialog', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: Dialog,
|
||||
transclude: {
|
||||
body: 'tplBody',
|
||||
title: '?tplTitle',
|
||||
body: '?tplBody',
|
||||
buttons: '?tplButtons'
|
||||
},
|
||||
bindings: {
|
||||
message: '@?',
|
||||
onResponse: '&?',
|
||||
onAccept: '&?'
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
& > form {
|
||||
padding: $spacing-lg;
|
||||
|
||||
& > h6 {
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
& > .body > tpl-body {
|
||||
display: block;
|
||||
min-width: 256px;
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
<div ng-show="$ctrl.showFilter" class="filter">
|
||||
<vn-textfield
|
||||
ng-model="$ctrl.search"
|
||||
class="dense search"
|
||||
ng-blur="$ctrl.onFocusOut()"
|
||||
placeholder="{{::'Search' | translate}}"
|
||||
autocomplete="off">
|
||||
</vn-textfield>
|
||||
</div>
|
||||
<div class="list" tabindex="-1">
|
||||
<ul
|
||||
class="dropdown"
|
||||
ng-click="$ctrl.onContainerClick($event)">
|
||||
</ul>
|
||||
<div
|
||||
ng-if="$ctrl.statusText"
|
||||
ng-click="$ctrl.onLoadMoreClick($event)"
|
||||
class="status"
|
||||
translate>
|
||||
{{$ctrl.statusText}}
|
||||
<default>
|
||||
<div ng-show="$ctrl.showFilter" class="filter">
|
||||
<vn-textfield
|
||||
ng-model="$ctrl.search"
|
||||
class="dense search"
|
||||
ng-blur="$ctrl.onFocusOut()"
|
||||
placeholder="{{::'Search' | translate}}"
|
||||
autocomplete="off">
|
||||
</vn-textfield>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list" tabindex="-1">
|
||||
<ul
|
||||
class="dropdown"
|
||||
ng-click="$ctrl.onContainerClick($event)">
|
||||
</ul>
|
||||
<div
|
||||
ng-if="$ctrl.statusText"
|
||||
ng-click="$ctrl.onLoadMoreClick($event)"
|
||||
class="status"
|
||||
translate>
|
||||
{{$ctrl.statusText}}
|
||||
</div>
|
||||
</div>
|
||||
</default>
|
|
@ -1,7 +1,6 @@
|
|||
import './style.scss';
|
||||
import ngModule from '../../module';
|
||||
import Popover from '../popover';
|
||||
import template from './index.html';
|
||||
import ArrayModel from '../array-model/array-model';
|
||||
import CrudModel from '../crud-model/crud-model';
|
||||
import {mergeWhere} from 'vn-loopback/util/filter';
|
||||
|
@ -21,7 +20,6 @@ export default class DropDown extends Popover {
|
|||
this.showLoadMore = true;
|
||||
this.showFilter = true;
|
||||
this.searchDelay = 300;
|
||||
this.fillDefaultSlot(template);
|
||||
}
|
||||
|
||||
get search() {
|
||||
|
@ -458,6 +456,7 @@ function getPosition(parent, event) {
|
|||
}
|
||||
|
||||
ngModule.vnComponent('vnDropDown', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: DropDown,
|
||||
transclude: {
|
||||
tplItem: '?tplItem'
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="control"></div>
|
||||
<div class="fix suffix"></div>
|
||||
<label>
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate>{{$ctrl.label}}</span>
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -9,12 +9,6 @@ import Component from '../../lib/component';
|
|||
* @property {Boolean} disabled Put component in disabled mode
|
||||
*/
|
||||
export default class FormInput extends Component {
|
||||
constructor($element, $scope) {
|
||||
super($element, $scope);
|
||||
this.classList = this.element.classList;
|
||||
this.classList.add(...this.constructor.$classNames);
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
// XXX: Compatibility with old inputs
|
||||
let attrs = this.$element[0].attributes;
|
||||
|
|
|
@ -7,6 +7,8 @@ vn-icon {
|
|||
& > i,
|
||||
& > i.material-icons {
|
||||
display: block;
|
||||
}
|
||||
& > i.material-icons {
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
<div class="fix suffix"></div>
|
||||
<label>
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate>{{$ctrl.label}}</span>
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="control"></div>
|
||||
<div class="fix suffix"></div>
|
||||
<label>
|
||||
<span translate>{{::$ctrl.label}}</span>
|
||||
<span translate>{{$ctrl.label}}</span>
|
||||
<span class="required">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -1,27 +1,11 @@
|
|||
@import "./effects";
|
||||
/*
|
||||
ul.menu {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
padding-top: $spacing-md;
|
||||
margin: 0;
|
||||
font-size: inherit;
|
||||
|
||||
& > li > a {
|
||||
@extend %clickable;
|
||||
display: block;
|
||||
color: inherit;
|
||||
padding: 9px 32px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
vn-list,
|
||||
.vn-list {
|
||||
display: block;
|
||||
max-width: $width-sm;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
padding: $spacing-sm 0;
|
||||
list-style-type: none;
|
||||
|
||||
vn-list,
|
||||
|
@ -32,6 +16,8 @@ vn-list,
|
|||
}
|
||||
}
|
||||
&.separated {
|
||||
padding: 0;
|
||||
|
||||
vn-item,
|
||||
.vn-item {
|
||||
border-bottom: $border-thin-light;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import ngModule from '../../module';
|
||||
import Popup from '../popup';
|
||||
import template from './index.html';
|
||||
import isMobile from '../../lib/is-mobile';
|
||||
import './style.scss';
|
||||
|
||||
|
@ -8,24 +7,27 @@ import './style.scss';
|
|||
* A simple popover.
|
||||
*
|
||||
* @property {HTMLElement} parent The parent element to show drop down relative to
|
||||
* @property {HTMLElement} content Element holding the popover content
|
||||
*
|
||||
* @event open Thrown when popover is displayed
|
||||
* @event close Thrown when popover is hidden
|
||||
*/
|
||||
export default class Popover extends Popup {
|
||||
constructor($element, $, $transclude) {
|
||||
super($element, $, $transclude);
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.displayMode = isMobile ? 'centered' : 'relative';
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the popover emitting the open signal. If a parent is specified
|
||||
* it is shown in a visible relative position to it.
|
||||
*
|
||||
* @param {HTMLElement} parent Overrides the parent property
|
||||
* @param {HTMLElement|Event} parent Overrides the parent property
|
||||
*/
|
||||
show(parent) {
|
||||
if (parent instanceof Event)
|
||||
parent = event.target;
|
||||
|
||||
if (parent) this.parent = parent;
|
||||
super.show();
|
||||
this.content = this.popup.querySelector('.content');
|
||||
|
@ -44,7 +46,6 @@ export default class Popover extends Popup {
|
|||
// Bug #2147 Popover loses parent location
|
||||
set parent(value) {
|
||||
this.__parent = value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
const parentRect = value.getBoundingClientRect();
|
||||
|
@ -115,3 +116,7 @@ export default class Popover extends Popup {
|
|||
ngModule.vnComponent('vnPopover', {
|
||||
controller: Popover
|
||||
});
|
||||
|
||||
ngModule.run(['$compile', function($compile) {
|
||||
Popover.prototype.contentLinkFn = $compile(require('./index.html'));
|
||||
}]);
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import template from './index.html';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Base class for windows displayed over application content.
|
||||
*/
|
||||
export default class Popup extends Component {
|
||||
constructor($element, $scope, $transclude) {
|
||||
super($element, $scope);
|
||||
this.$transclude = $transclude;
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this._shown = false;
|
||||
this.displayMode = 'centered';
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
|
@ -34,7 +31,7 @@ export default class Popup extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Displays the dialog to the user.
|
||||
* Displays the popup.
|
||||
*/
|
||||
show() {
|
||||
if (this.shown) return;
|
||||
|
@ -45,11 +42,13 @@ export default class Popup extends Component {
|
|||
this.onClose();
|
||||
}
|
||||
|
||||
let linkFn = this.$compile(this.template);
|
||||
this.$contentScope = this.$.$new();
|
||||
this.popup = linkFn(this.$contentScope, null,
|
||||
this.contentLinkFn(
|
||||
this.$contentScope,
|
||||
element => this.popup = element[0],
|
||||
{parentBoundTranscludeFn: this.$transclude}
|
||||
)[0];
|
||||
);
|
||||
|
||||
this.windowEl = this.popup.querySelector('.window');
|
||||
this.windowEl.focus();
|
||||
|
||||
|
@ -75,7 +74,7 @@ export default class Popup extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Hides the dialog calling the response handler.
|
||||
* Hides the popup.
|
||||
*/
|
||||
hide() {
|
||||
if (!this.shown) return;
|
||||
|
@ -96,6 +95,11 @@ export default class Popup extends Component {
|
|||
this.emit('closeStart');
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when closing transition ends and popup is not visible, it can
|
||||
* be overriden by child classes (calling the super) to perform additional
|
||||
* actions.
|
||||
*/
|
||||
onClose() {
|
||||
this.closeTimeout = null;
|
||||
this.popup.remove();
|
||||
|
@ -127,5 +131,10 @@ ngModule.vnComponent('vnPopup', {
|
|||
transclude: true,
|
||||
bindings: {
|
||||
shown: '=?'
|
||||
}
|
||||
},
|
||||
installClasses: false
|
||||
});
|
||||
|
||||
ngModule.run(['$compile', function($compile) {
|
||||
Popup.prototype.contentLinkFn = $compile(require('./index.html'));
|
||||
}]);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
@import "variables";
|
||||
|
||||
vn-scroll-up {
|
||||
top: 88px;
|
||||
right: 32px;
|
||||
right: 0;
|
||||
top: $topbar-height;
|
||||
margin: $float-spacing;
|
||||
display: none;
|
||||
position: fixed;
|
||||
}
|
|
@ -5,6 +5,7 @@ vn-spinner {
|
|||
min-height: 28px;
|
||||
min-width: 28px;
|
||||
color: $color-main;
|
||||
overflow: hidden;
|
||||
|
||||
& > .loader {
|
||||
position: relative;
|
||||
|
|
|
@ -9,7 +9,6 @@ function vnAcl(aclService) {
|
|||
priority: -1,
|
||||
link: function(_, $element, $attrs) {
|
||||
acls = $attrs.vnAcl.split(',').map(i => i.trim());
|
||||
|
||||
if (acls[0] == '') return;
|
||||
|
||||
let action = $attrs.vnAclAction || 'disable';
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
/*
|
||||
* Registers a handler for the click event and stops propagation when event
|
||||
* is thrown, mainly when nesting clickable elements wich ignore the
|
||||
* Event.defaultPrevented property, like ui-sref.
|
||||
*/
|
||||
export function directive($parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs) {
|
||||
const fn = $parse(attrs.vnClickStop);
|
||||
element.on('click', function(event) {
|
||||
fn(scope, {$event: event});
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
directive.$inject = ['$parse'];
|
||||
|
||||
ngModule.directive('vnClickStop', directive);
|
|
@ -2,6 +2,7 @@ import './id';
|
|||
import './focus';
|
||||
import './dialog';
|
||||
import './popover';
|
||||
import './click-stop';
|
||||
import './rule';
|
||||
import './acl';
|
||||
import './on-error-src';
|
||||
|
|
|
@ -15,6 +15,7 @@ describe('Directive focus', () => {
|
|||
$element[0].focus = jasmine.createSpy('focus');
|
||||
$element[0].select = jasmine.createSpy('select');
|
||||
$compile($element)($scope);
|
||||
$scope.$apply();
|
||||
$flushPendingTasks();
|
||||
});
|
||||
};
|
||||
|
@ -37,7 +38,6 @@ describe('Directive focus', () => {
|
|||
it('should call select function on the element', () => {
|
||||
let html = `<input vn-focus></input>`;
|
||||
compile(html);
|
||||
$scope.$apply();
|
||||
|
||||
expect($element[0].select).toHaveBeenCalledWith();
|
||||
});
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
</vn-icon-button>
|
||||
<vn-dialog
|
||||
class="modal-form"
|
||||
vn-id="uvc">
|
||||
vn-id="uvc"
|
||||
message="Fields to show">
|
||||
<tpl-body>
|
||||
<vn-horizontal class="vn-pa-md header">
|
||||
<h5><span translate>Fields to show</span></h5>
|
||||
</vn-horizontal>
|
||||
<div class="vn-pa-md">
|
||||
<vn-horizontal ng-repeat="field in fields">
|
||||
<vn-check
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
/**
|
||||
* Formats the value as id.
|
||||
*
|
||||
* @return {String} The formated value
|
||||
*/
|
||||
export default function id() {
|
||||
return function(value) {
|
||||
if (value == null || value === '')
|
||||
return '';
|
||||
return `#${value}`;
|
||||
};
|
||||
}
|
||||
ngModule.filter('id', id);
|
|
@ -4,3 +4,4 @@ import './dash-if-empty';
|
|||
import './percentage';
|
||||
import './currency';
|
||||
import './zero-fill';
|
||||
import './id';
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
describe('Id filter', () => {
|
||||
let idFilter;
|
||||
|
||||
beforeEach(ngModule('vnCore'));
|
||||
|
||||
beforeEach(inject(_idFilter_ => {
|
||||
idFilter = _idFilter_;
|
||||
}));
|
||||
|
||||
it('should return empty string for input null', () => {
|
||||
expect(idFilter(null)).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty stringfor input empty', () => {
|
||||
expect(idFilter('')).toBe('');
|
||||
});
|
||||
|
||||
it('should prefix a pad character', () => {
|
||||
expect(idFilter('123')).toBe('#123');
|
||||
});
|
||||
});
|
|
@ -11,14 +11,29 @@ export default class Component extends EventEmitter {
|
|||
*
|
||||
* @param {HTMLElement} $element The main component element
|
||||
* @param {$rootScope.Scope} $scope The element scope
|
||||
* @param {Function} $transclude The transclusion function
|
||||
*/
|
||||
constructor($element, $scope) {
|
||||
constructor($element, $scope, $transclude) {
|
||||
super();
|
||||
this.$ = $scope;
|
||||
|
||||
if (!$element) return;
|
||||
this.element = $element[0];
|
||||
this.element.$ctrl = this;
|
||||
this.$element = $element;
|
||||
this.$ = $scope;
|
||||
this.$transclude = $transclude;
|
||||
this.classList = this.element.classList;
|
||||
|
||||
const constructor = this.constructor;
|
||||
const $options = constructor.$options;
|
||||
|
||||
if ($options && $options.installClasses)
|
||||
this.classList.add(...this.constructor.$classNames);
|
||||
|
||||
if ($transclude && constructor.slotTemplates) {
|
||||
for (let slotTemplate of constructor.slotTemplates)
|
||||
this.fillSlots(slotTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
$postLink() {
|
||||
|
@ -26,7 +41,7 @@ export default class Component extends EventEmitter {
|
|||
let attrs = this.$element[0].attributes;
|
||||
let $scope = this.$;
|
||||
for (let attr of attrs) {
|
||||
if (attr.name.substr(0, 2) !== 'on') continue;
|
||||
if (!attr.name.startsWith('on-')) continue;
|
||||
let eventName = kebabToCamel(attr.name.substr(3));
|
||||
let callback = locals => $scope.$parent.$eval(attr.nodeValue, locals);
|
||||
this.on(eventName, callback);
|
||||
|
@ -58,6 +73,72 @@ export default class Component extends EventEmitter {
|
|||
return this.$translate.instant(string, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the default transclude slot.
|
||||
*
|
||||
* @param {JQElement|String} template The slot template
|
||||
*/
|
||||
fillDefaultSlot(template) {
|
||||
const linkFn = this.$compile(template);
|
||||
this.$transclude.$$boundTransclude = this.createBoundTranscludeFn(linkFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills a named transclude slot.
|
||||
*
|
||||
* @param {String} slot The trasnclude slot name
|
||||
* @param {JQElement|String} template The slot template
|
||||
*/
|
||||
fillSlot(slot, template) {
|
||||
const linkFn = this.$compile(template);
|
||||
const slots = this.$transclude.$$boundTransclude.$$slots;
|
||||
slots[slot] = this.createBoundTranscludeFn(linkFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills component transclude slots using the passed HTML template string
|
||||
* as source.
|
||||
*
|
||||
* @param {String} template The HTML template string
|
||||
*/
|
||||
fillSlots(template) {
|
||||
const name = this.constructor.$options.name;
|
||||
const transclude = this.constructor.$options.transclude;
|
||||
|
||||
if (!transclude)
|
||||
throw new Error(`No transclusion option defined in '${name}'`);
|
||||
if (!this.$transclude)
|
||||
throw new Error(`No $transclude injected in '${name}'`);
|
||||
|
||||
let slotMap = {};
|
||||
for (let slotName in transclude) {
|
||||
let slotTag = transclude[slotName].match(/\w+$/)[0];
|
||||
slotMap[slotTag] = slotName;
|
||||
}
|
||||
|
||||
const $template = angular.element(template);
|
||||
for (let i = 0; i < $template.length; i++) {
|
||||
let slotElement = $template[i];
|
||||
if (slotElement.nodeType != Node.ELEMENT_NODE) continue;
|
||||
let tagName = kebabToCamel(slotElement.tagName.toLowerCase());
|
||||
|
||||
if (tagName == 'default')
|
||||
this.fillDefaultSlot(slotElement.childNodes);
|
||||
else {
|
||||
let slotName = slotMap[tagName];
|
||||
if (!slotName)
|
||||
throw new Error(`No slot found for '${tagName}' in '${name}'`);
|
||||
this.fillSlot(slotName, slotElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a bounded transclude function from a linking function.
|
||||
*
|
||||
* @param {Function} linkFn The linking function
|
||||
* @return {Function} The bounded transclude function
|
||||
*/
|
||||
createBoundTranscludeFn(linkFn) {
|
||||
let scope = this.$;
|
||||
let previousBoundTranscludeFn = this.$transclude.$$boundTransclude;
|
||||
|
@ -78,17 +159,6 @@ export default class Component extends EventEmitter {
|
|||
return vnBoundTranscludeFn;
|
||||
}
|
||||
|
||||
fillDefaultSlot(template) {
|
||||
let linkFn = this.$compile(template);
|
||||
this.$transclude.$$boundTransclude = this.createBoundTranscludeFn(linkFn);
|
||||
}
|
||||
|
||||
fillSlot(slot, template) {
|
||||
let slots = this.$transclude.$$boundTransclude.$$slots;
|
||||
let linkFn = this.$compile(template);
|
||||
slots[slot] = this.createBoundTranscludeFn(linkFn);
|
||||
}
|
||||
|
||||
copySlot(slot, $transclude) {
|
||||
this.$transclude.$$boundTransclude.$$slots[slot] =
|
||||
$transclude.$$boundTransclude.$$slots[slot];
|
||||
|
@ -96,44 +166,25 @@ export default class Component extends EventEmitter {
|
|||
}
|
||||
Component.$inject = ['$element', '$scope'];
|
||||
|
||||
function runFn(
|
||||
$translate,
|
||||
$q,
|
||||
$http,
|
||||
$state,
|
||||
$stateParams,
|
||||
$timeout,
|
||||
$transitions,
|
||||
$compile,
|
||||
$filter,
|
||||
$interpolate,
|
||||
$window,
|
||||
vnApp,
|
||||
vnToken,
|
||||
vnConfig,
|
||||
aclService) {
|
||||
Object.assign(Component.prototype, {
|
||||
$translate,
|
||||
$q,
|
||||
$http,
|
||||
$state,
|
||||
$params: $stateParams,
|
||||
$timeout,
|
||||
$transitions,
|
||||
$compile,
|
||||
$filter,
|
||||
$interpolate,
|
||||
$window,
|
||||
vnApp,
|
||||
vnToken,
|
||||
vnConfig,
|
||||
aclService
|
||||
/*
|
||||
* Automatically adds the most used services to the prototype, so they are
|
||||
* available as component properties.
|
||||
*/
|
||||
function runFn(...args) {
|
||||
const proto = Component.prototype;
|
||||
|
||||
for (let i = 0; i < runFn.$inject.length; i++)
|
||||
proto[runFn.$inject[i]] = args[i];
|
||||
|
||||
Object.assign(proto, {
|
||||
$params: proto.$stateParams
|
||||
});
|
||||
}
|
||||
runFn.$inject = [
|
||||
'$translate',
|
||||
'$q',
|
||||
'$http',
|
||||
'$httpParamSerializer',
|
||||
'$state',
|
||||
'$stateParams',
|
||||
'$timeout',
|
||||
|
@ -145,6 +196,7 @@ runFn.$inject = [
|
|||
'vnApp',
|
||||
'vnToken',
|
||||
'vnConfig',
|
||||
'vnModules',
|
||||
'aclService'
|
||||
];
|
||||
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
import {ng, ngDeps} from './vendor';
|
||||
import {camelToKebab} from './lib/string';
|
||||
|
||||
/**
|
||||
* Extended component options.
|
||||
*
|
||||
* @property {Boolean} installClassses Whether to install CSS classes equivalent to the component's and parents name
|
||||
* @property {String} slotTemplate HTML template used to fill component transclude slots
|
||||
*/
|
||||
const defaultOptions = {
|
||||
installClasses: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Acts like native Module.component() function but merging component options
|
||||
* with parent component options. This method establishes the $options property
|
||||
|
@ -17,7 +27,7 @@ import {camelToKebab} from './lib/string';
|
|||
function vnComponent(name, options) {
|
||||
let controller = options.controller;
|
||||
let parent = Object.getPrototypeOf(controller);
|
||||
let parentOptions = parent.$options || {};
|
||||
let parentOptions = parent.$options || defaultOptions;
|
||||
|
||||
let parentTransclude = parentOptions.transclude;
|
||||
let transclude = parentTransclude instanceof Object
|
||||
|
@ -32,10 +42,11 @@ function vnComponent(name, options) {
|
|||
} else if (options.transclude !== undefined)
|
||||
transclude = options.transclude;
|
||||
|
||||
let mergedOptions = Object.assign({},
|
||||
let $options = Object.assign({},
|
||||
parentOptions,
|
||||
options,
|
||||
{
|
||||
name,
|
||||
transclude,
|
||||
bindings: Object.assign({},
|
||||
parentOptions.bindings,
|
||||
|
@ -47,13 +58,17 @@ function vnComponent(name, options) {
|
|||
)
|
||||
}
|
||||
);
|
||||
controller.$options = mergedOptions;
|
||||
|
||||
let parentSlotTemplates = parent.slotTemplates || [];
|
||||
if (options.slotTemplate)
|
||||
controller.slotTemplates = parentSlotTemplates.concat([options.slotTemplate]);
|
||||
|
||||
let classNames = [camelToKebab(name)];
|
||||
if (parent.$classNames) classNames = classNames.concat(parent.$classNames);
|
||||
controller.$classNames = classNames;
|
||||
|
||||
return this.component(name, mergedOptions);
|
||||
controller.$options = $options;
|
||||
return this.component(name, $options);
|
||||
}
|
||||
|
||||
const ngModuleFn = ng.module;
|
||||
|
@ -72,33 +87,12 @@ export function config($translateProvider, $translatePartialLoaderProvider, $ani
|
|||
// For CSS browser targeting
|
||||
document.documentElement.setAttribute('data-browser', navigator.userAgent);
|
||||
|
||||
$translatePartialLoaderProvider.addPart('core');
|
||||
|
||||
let conf = {urlTemplate: '/locale/{part}/{lang}.json'};
|
||||
|
||||
let fallbackLang = 'es';
|
||||
let langs = ['en', 'es'];
|
||||
let langAliases = {
|
||||
en_US: 'en',
|
||||
en_GB: 'en',
|
||||
es_ES: 'es',
|
||||
es_AR: 'es'
|
||||
};
|
||||
|
||||
$translateProvider
|
||||
.useSanitizeValueStrategy('escape')
|
||||
.useLoader('$translatePartialLoader', conf)
|
||||
.registerAvailableLanguageKeys(langs, langAliases)
|
||||
// FIXME: Circular dependency due to vnInterceptor
|
||||
// .fallbackLanguage(fallbackLang)
|
||||
.determinePreferredLanguage(() => {
|
||||
let locale = $translateProvider.resolveClientLocale();
|
||||
if (langs.indexOf(locale) !== -1)
|
||||
return locale;
|
||||
if (langAliases[locale])
|
||||
return langAliases[locale];
|
||||
return fallbackLang;
|
||||
.useLoader('$translatePartialLoader', {
|
||||
urlTemplate: '/locale/{part}/{lang}.json'
|
||||
});
|
||||
$translatePartialLoaderProvider.addPart('core');
|
||||
|
||||
$animateProvider.customFilter(
|
||||
node => node.tagName == 'UI-VIEW');
|
||||
|
|
|
@ -10,15 +10,10 @@ export default class Modules {
|
|||
});
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.modules = null;
|
||||
}
|
||||
|
||||
get() {
|
||||
if (this.modules)
|
||||
return this.modules;
|
||||
|
||||
fetch() {
|
||||
const map = {};
|
||||
const modules = [];
|
||||
|
||||
for (let mod of this.$window.routes) {
|
||||
if (!mod || !mod.routes) continue;
|
||||
|
||||
|
@ -32,12 +27,15 @@ export default class Modules {
|
|||
if (res) keyBind = res.key.toUpperCase();
|
||||
}
|
||||
|
||||
modules.push({
|
||||
const module = {
|
||||
name: mod.name || mod.module,
|
||||
icon: mod.icon || null,
|
||||
route,
|
||||
keyBind
|
||||
});
|
||||
};
|
||||
|
||||
modules.push(module);
|
||||
map[mod.module] = mod;
|
||||
}
|
||||
|
||||
const sortedModules = modules.sort((a, b) => {
|
||||
|
@ -46,9 +44,23 @@ export default class Modules {
|
|||
return translatedNameA.localeCompare(translatedNameB);
|
||||
});
|
||||
this.modules = sortedModules;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.modules = null;
|
||||
this.map = null;
|
||||
}
|
||||
|
||||
get() {
|
||||
if (!this.modules) this.fetch();
|
||||
return this.modules;
|
||||
}
|
||||
|
||||
getMap() {
|
||||
if (!this.map) this.fetch();
|
||||
return this.map;
|
||||
}
|
||||
}
|
||||
Modules.$inject = ['aclService', '$window', '$translate'];
|
||||
|
||||
|
|
|
@ -39,3 +39,8 @@
|
|||
/* Support for IE. */
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
[class^="icon-"] {
|
||||
padding: .1em;
|
||||
font-size: .833em;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,19 @@
|
|||
html [vn-horizontal], vn-horizontal, .vn-horizontal,
|
||||
html [vn-vertical], vn-vertical, .vn-vertical {
|
||||
display: flex;
|
||||
|
||||
& > * {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
html [vn-horizontal], vn-horizontal, .vn-horizontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
vn-horizontal[reverse] {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
html [vn-vertical], vn-vertical, .vn-vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
vn-vertical[reverse] {
|
||||
|
||||
html [reverse] {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
html [wrap] {
|
||||
|
@ -26,27 +28,11 @@ html [wrap-reverse] {
|
|||
|
||||
/* Horizontal & vertical childs */
|
||||
|
||||
html [vn-auto],
|
||||
html [vn-none],
|
||||
html [vn-one],
|
||||
html [vn-two],
|
||||
html [vn-three],
|
||||
html [vn-four],
|
||||
html [vn-five],
|
||||
html [vn-six],
|
||||
html [vn-seven],
|
||||
html [vn-eight],
|
||||
html [vn-nine],
|
||||
html [vn-ten],
|
||||
html [vn-eleven],
|
||||
html [vn-twelve]{
|
||||
flex-basis: .1px;
|
||||
}
|
||||
html [vn-auto], vn-auto, .vn-auto {
|
||||
flex-basis: auto;
|
||||
flex: initial;
|
||||
}
|
||||
html [vn-none], vn-none, .vn-none {
|
||||
flex: none;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
html [vn-one], vn-one, .vn-one {
|
||||
flex: 1;
|
||||
|
|
|
@ -4,6 +4,7 @@ $font-size: 12pt;
|
|||
$menu-width: 256px;
|
||||
$topbar-height: 56px;
|
||||
$mobile-width: 800px;
|
||||
$float-spacing: 20px;
|
||||
|
||||
// Width
|
||||
|
||||
|
|
|
@ -6,5 +6,4 @@
|
|||
ng-if="!$ctrl.showLayout">
|
||||
</ui-view>
|
||||
<vn-snackbar vn-id="snackbar"></vn-snackbar>
|
||||
|
||||
<!-- <vn-debug-info></vn-debug-info> -->
|
||||
<vn-debug-info></vn-debug-info>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<default>
|
||||
<div
|
||||
ng-transclude="descriptor"
|
||||
class="descriptor-wrapper">
|
||||
</div>
|
||||
</default>
|
|
@ -0,0 +1,28 @@
|
|||
import ngModule from '../../module';
|
||||
import Popover from 'core/components/popover';
|
||||
import './style.scss';
|
||||
|
||||
export default class DescriptorPopover extends Popover {
|
||||
show(parent, id) {
|
||||
super.show(parent);
|
||||
|
||||
this.id = id;
|
||||
this.descriptor = this.content.querySelector('.vn-descriptor').$ctrl;
|
||||
this.descriptor.load(id)
|
||||
.then(() => this.$.$applyAsync(() => this.relocate()));
|
||||
}
|
||||
|
||||
hide() {
|
||||
super.hide();
|
||||
this.id = null;
|
||||
this.descriptor = null;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnDescriptorPopover', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: DescriptorPopover,
|
||||
transclude: {
|
||||
descriptor: '?slotDescriptor'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
@import "variables";
|
||||
|
||||
.vn-descriptor-popover {
|
||||
vn-descriptor-content > .descriptor {
|
||||
width: 260px;
|
||||
|
||||
& > .header > a:first-child {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,40 @@
|
|||
<a ng-repeat="button in $ctrl.links"
|
||||
vn-tooltip="{{::button.tooltip}}"
|
||||
class="vn-button colored"
|
||||
ui-sref="{{::button.state}}">
|
||||
<vn-icon
|
||||
icon="{{::button.icon}}">
|
||||
</vn-icon>
|
||||
</a>
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.descriptor.canceler"
|
||||
enable="true">
|
||||
</vn-spinner>
|
||||
<div
|
||||
ng-if="!$ctrl.descriptor.canceler"
|
||||
class="descriptor">
|
||||
<div class="header">
|
||||
<a
|
||||
translate-attr="{title: 'Go to module index'}"
|
||||
ui-sref="{{::$ctrl.module}}.index"
|
||||
name="goToModuleIndex">
|
||||
<vn-icon icon="{{$ctrl.moduleMap[$ctrl.module].icon}}"></vn-icon>
|
||||
</a>
|
||||
<a
|
||||
translate-attr="{title: 'Preview'}"
|
||||
ui-sref="{{::$ctrl.module}}.card.summary({id: $ctrl.descriptor.id})">
|
||||
<vn-icon icon="desktop_windows"></vn-icon>
|
||||
</a>
|
||||
<vn-icon-button
|
||||
ng-class="::{invisible: !$ctrl.$transclude.isSlotFilled('menu')}"
|
||||
icon="more_vert"
|
||||
vn-popover="menu">
|
||||
</vn-icon-button>
|
||||
</div>
|
||||
<vn-menu vn-id="menu">
|
||||
<vn-list ng-transclude="menu"></vn-list>
|
||||
</vn-menu>
|
||||
<div ng-transclude="before"></div>
|
||||
<div class="body">
|
||||
<div class="top">
|
||||
<h5>{{$ctrl.description}}</h5>
|
||||
<div class="text-secondary">
|
||||
{{$ctrl.descriptor.id | id}}
|
||||
</div>
|
||||
</div>
|
||||
<div ng-transclude="body"></div>
|
||||
</div>
|
||||
<div ng-transclude="after"></div>
|
||||
</div>
|
|
@ -1,12 +1,141 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
import './quick-link';
|
||||
|
||||
export default class QuickLinks {}
|
||||
/**
|
||||
* Small card with basing entity information and actions.
|
||||
*/
|
||||
export default class Descriptor extends Component {
|
||||
$postLink() {
|
||||
const content = this.element.querySelector('vn-descriptor-content');
|
||||
if (!content) throw new Error('Directive vnDescriptorContent not found');
|
||||
|
||||
ngModule.component('vnQuickLinks', {
|
||||
template: require('./index.html'),
|
||||
controller: QuickLinks,
|
||||
angular.element(content)
|
||||
.controller('vnDescriptorContent')
|
||||
.descriptor = this;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
set id(value) {
|
||||
this.load(value);
|
||||
}
|
||||
|
||||
get entity() {
|
||||
return this._entity;
|
||||
}
|
||||
|
||||
set entity(value) {
|
||||
this._entity = value;
|
||||
this._id = value && value.id;
|
||||
}
|
||||
|
||||
load(id) {
|
||||
if (id == this._id)
|
||||
return this.$q.resolve();
|
||||
|
||||
this._id = id;
|
||||
|
||||
if (!id) {
|
||||
this.entity = null;
|
||||
return this.$q.resolve();
|
||||
}
|
||||
|
||||
return this.loadData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the descriptor data. Should be implemented or overriden by child
|
||||
* classes.
|
||||
*/
|
||||
loadData() {
|
||||
throw new Error('DescriptorPopover::loadData() method not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a cancellable request.
|
||||
*
|
||||
* @param {String} url The http path
|
||||
* @param {Object} options The request options
|
||||
* @return {Promise} Resolved with request response
|
||||
*/
|
||||
getData(url, options) {
|
||||
if (this.canceler) this.canceler.resolve();
|
||||
this.canceler = this.$q.defer();
|
||||
this.entity = null;
|
||||
|
||||
options = Object.assign(options || {}, {
|
||||
timeout: this.canceler.promise
|
||||
});
|
||||
|
||||
return this.$http.get(url, options)
|
||||
.finally(() => this.canceler = null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a report in another window, automatically adds the authorization
|
||||
* token to params.
|
||||
*
|
||||
* @param {String} report The report name
|
||||
* @param {Object} params The report parameters
|
||||
*/
|
||||
showReport(report, params) {
|
||||
params = Object.assign({
|
||||
authorization: this.vnToken.token
|
||||
}, params);
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
window.open(`api/report/${report}?${serializedParams}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email displaying a notification when it's sent.
|
||||
*
|
||||
* @param {String} report The email report name
|
||||
* @param {Object} params The email parameters
|
||||
* @return {Promise} Promise resolved when it's sent
|
||||
*/
|
||||
sendEmail(report, params) {
|
||||
return this.$http.get(`email/${report}`, {params})
|
||||
.then(() => this.vnApp.showMessage(this.$t('Notification sent!')));
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnDescriptor', {
|
||||
controller: Descriptor,
|
||||
bindings: {
|
||||
links: '<?'
|
||||
entity: '<?',
|
||||
id: '<?'
|
||||
},
|
||||
transclude: {
|
||||
btnOne: '?btnOne',
|
||||
btnTwo: '?btnTwo',
|
||||
btnThree: '?btnThree'
|
||||
}
|
||||
});
|
||||
|
||||
export class DescriptorContent {
|
||||
constructor($transclude, vnModules) {
|
||||
this.$transclude = $transclude;
|
||||
this.moduleMap = vnModules.getMap();
|
||||
}
|
||||
}
|
||||
DescriptorContent.$inject = ['$transclude', 'vnModules'];
|
||||
|
||||
ngModule.component('vnDescriptorContent', {
|
||||
template: require('./index.html'),
|
||||
controller: DescriptorContent,
|
||||
bindings: {
|
||||
module: '@',
|
||||
description: '<',
|
||||
descriptor: '<?'
|
||||
},
|
||||
transclude: {
|
||||
body: 'slotBody',
|
||||
before: '?slotBefore',
|
||||
after: '?slotAfter',
|
||||
menu: '?slotMenu'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<a
|
||||
ui-sref="{{::$ctrl.state[0]}}($ctrl.state[1])"
|
||||
vn-tooltip="{{::$ctrl.tooltip}}"
|
||||
class="vn-button colored">
|
||||
<vn-icon
|
||||
icon="{{::$ctrl.icon}}">
|
||||
</vn-icon>
|
||||
</a>
|
|
@ -0,0 +1,13 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
export default class QuickLink {}
|
||||
|
||||
ngModule.component('vnQuickLink', {
|
||||
template: require('./quick-link.html'),
|
||||
controller: QuickLink,
|
||||
bindings: {
|
||||
state: '<?',
|
||||
icon: '@?',
|
||||
tooltip: '@?'
|
||||
}
|
||||
});
|
|
@ -2,83 +2,102 @@
|
|||
@import "./effects";
|
||||
@import "./variables";
|
||||
|
||||
.vn-descriptor {
|
||||
box-shadow: 0 1px 3px $color-shadow;
|
||||
vn-descriptor-content {
|
||||
display: block;
|
||||
|
||||
& > .header {
|
||||
display: flex;
|
||||
background: $color-main;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
color: $color-font-dark;
|
||||
|
||||
& > * {
|
||||
@extend %clickable;
|
||||
min-width: 45px;
|
||||
height: 45px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: inherit;
|
||||
|
||||
& > vn-icon {
|
||||
padding: 10px;
|
||||
}
|
||||
vn-icon {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
& > vn-spinner {
|
||||
display: block;
|
||||
height: 40px;
|
||||
padding: $spacing-md;
|
||||
}
|
||||
& > .body {
|
||||
padding: $spacing-sm;
|
||||
& > div {
|
||||
display: block;
|
||||
box-shadow: 0 1px 3px $color-shadow;
|
||||
|
||||
& > * {
|
||||
padding: $spacing-sm;
|
||||
}
|
||||
& > .attributes > h5 {
|
||||
padding-bottom: $spacing-sm;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
& > .icons {
|
||||
& > .header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
|
||||
& > vn-icon {
|
||||
padding: $spacing-sm;
|
||||
color: $color-marginal;
|
||||
font-size: 1.5rem;
|
||||
|
||||
&.bright {
|
||||
color: $color-main;
|
||||
opacity: 1;
|
||||
background: $color-main;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
color: $color-font-dark;
|
||||
|
||||
& > * {
|
||||
display: flex;
|
||||
min-width: 45px;
|
||||
height: 45px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
& > a,
|
||||
& > vn-icon-button {
|
||||
@extend %clickable;
|
||||
color: inherit;
|
||||
|
||||
& > vn-icon {
|
||||
padding: 10px;
|
||||
}
|
||||
vn-icon {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.quicklinks,
|
||||
vn-quick-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& > a {
|
||||
padding: 0 $spacing-md;
|
||||
margin: 0 $spacing-sm;
|
||||
& > .body {
|
||||
display: block;
|
||||
padding: $spacing-md;
|
||||
|
||||
& > vn-icon {
|
||||
font-size: 1.75rem;
|
||||
padding: 0;
|
||||
& > .top {
|
||||
padding-bottom: $spacing-sm;
|
||||
|
||||
& > * {
|
||||
margin-bottom: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
& > div > slot-body {
|
||||
& > * {
|
||||
padding-bottom: $spacing-md;
|
||||
}
|
||||
& > :last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
& > .icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& > vn-icon {
|
||||
padding: $spacing-xs $spacing-sm;
|
||||
color: $color-marginal;
|
||||
font-size: 1.5rem;
|
||||
|
||||
&.bright {
|
||||
color: $color-main;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
& > .quicklinks {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
vn-quick-link > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 $spacing-md;
|
||||
margin: 0 $spacing-sm;
|
||||
|
||||
& > vn-icon {
|
||||
font-size: 1.75rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.vn-popover {
|
||||
.vn-descriptor > .header > a:first-child {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import './app/app';
|
||||
import './background/background';
|
||||
import './descriptor';
|
||||
import './descriptor-popover';
|
||||
import './home/home';
|
||||
import './layout';
|
||||
import './left-menu/left-menu';
|
||||
|
|
|
@ -39,18 +39,26 @@
|
|||
</vn-icon-button>
|
||||
</div>
|
||||
<vn-menu vn-id="apps-menu">
|
||||
<ul class="modules-menu vn-pa-sm">
|
||||
<li ui-sref="home">
|
||||
<vn-icon icon="home"></vn-icon>
|
||||
<span translate>Home</span>
|
||||
</li>
|
||||
<li
|
||||
<vn-list class="modules-menu">
|
||||
<a class="vn-item" ui-sref="home">
|
||||
<vn-item-section avatar>
|
||||
<vn-icon icon="home"></vn-icon>
|
||||
</vn-item-section>
|
||||
<vn-item-section translate>
|
||||
Home
|
||||
</vn-item-section>
|
||||
</a>
|
||||
<a class="vn-item"
|
||||
ng-repeat="mod in ::$ctrl.modules"
|
||||
ui-sref="{{::mod.route.state}}">
|
||||
<vn-icon icon="{{::mod.icon || 'photo'}}"></vn-icon>
|
||||
<span translate>{{::mod.name}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<vn-item-section avatar>
|
||||
<vn-icon icon="{{::mod.icon || 'photo'}}"></vn-icon>
|
||||
</vn-item-section>
|
||||
<vn-item-section translate>
|
||||
{{::mod.name}}
|
||||
</vn-item-section>
|
||||
</a>
|
||||
</vn-list>
|
||||
</vn-menu>
|
||||
<vn-user-popover
|
||||
vn-id="user-popover">
|
||||
|
@ -74,4 +82,5 @@
|
|||
</a>
|
||||
</vn-list>
|
||||
</vn-portal>
|
||||
<ui-view class="main-view"></ui-view>
|
||||
<ui-view class="main-view"></ui-view>
|
||||
<vn-scroll-up></vn-scroll-up>
|
|
@ -32,7 +32,7 @@ vn-layout {
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
padding-left: 6px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
& > vn-spinner {
|
||||
padding: 0 6px;
|
||||
|
@ -80,7 +80,7 @@ vn-layout {
|
|||
padding-right: $menu-width;
|
||||
}
|
||||
[fixed-bottom-right] {
|
||||
right: 64px + $menu-width;
|
||||
right: $menu-width;
|
||||
}
|
||||
}
|
||||
& > .main-view {
|
||||
|
@ -94,8 +94,9 @@ vn-layout {
|
|||
}
|
||||
[fixed-bottom-right] {
|
||||
position: fixed;
|
||||
bottom: 32px;
|
||||
right: 32px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: $float-spacing;
|
||||
}
|
||||
&.ng-enter {
|
||||
vn-side-menu {
|
||||
|
@ -133,7 +134,7 @@ vn-layout {
|
|||
padding-right: 0;
|
||||
}
|
||||
[fixed-bottom-right] {
|
||||
right: 32px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
ui-view > * {
|
||||
|
@ -142,29 +143,6 @@ vn-layout {
|
|||
}
|
||||
}
|
||||
}
|
||||
.vn-popover .modules-menu {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
color: $color-font-dark;
|
||||
|
||||
& > li {
|
||||
@extend %clickable-light;
|
||||
background-color: $color-main;
|
||||
margin-bottom: 9px;
|
||||
padding: 12px;
|
||||
border-radius: 1px;
|
||||
min-width: 128px;
|
||||
white-space: nowrap;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
& > vn-icon {
|
||||
padding-right: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
#user {
|
||||
font-size: 1.5rem;
|
||||
height: auto;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class="vn-item"
|
||||
ng-class="{active: item.active && !item.childs, expanded: item.active}"
|
||||
ng-click="$ctrl.setActive(item)">
|
||||
<vn-item-section avatar>
|
||||
<vn-item-section avatar>
|
||||
<vn-icon icon="{{::item.icon}}" ng-if="::item.icon"></vn-icon>
|
||||
</vn-item-section>
|
||||
<vn-item-section translate>
|
||||
|
|
|
@ -3,16 +3,12 @@
|
|||
@import "variables";
|
||||
|
||||
vn-left-menu {
|
||||
& > .vn-list {
|
||||
padding: $spacing-md 0;
|
||||
|
||||
& > li > .vn-item {
|
||||
& > [side] > vn-icon[icon="keyboard_arrow_down"] {
|
||||
transition: transform 200ms;
|
||||
}
|
||||
&.expanded > [side] > vn-icon[icon="keyboard_arrow_down"] {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
& > .vn-list > li > .vn-item {
|
||||
& > [side] > vn-icon[icon="keyboard_arrow_down"] {
|
||||
transition: transform 200ms;
|
||||
}
|
||||
&.expanded > [side] > vn-icon[icon="keyboard_arrow_down"] {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@ import './style.scss';
|
|||
* Base class for module cards.
|
||||
*/
|
||||
export default class ModuleCard extends Component {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.element.classList.add('vn-module-card');
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.reload();
|
||||
}
|
||||
|
|
|
@ -2,12 +2,7 @@ import ngModule from '../../module';
|
|||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
|
||||
export default class ModuleMain extends Component {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.element.classList.add('vn-module-main');
|
||||
}
|
||||
}
|
||||
export default class ModuleMain extends Component {}
|
||||
|
||||
ngModule.vnComponent('vnModuleMain', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -2,17 +2,7 @@ import ngModule from '../../module';
|
|||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
|
||||
export default class Section extends Component {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.element.classList.add('vn-section');
|
||||
}
|
||||
|
||||
stopEvent(event) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
export default class Section extends Component {}
|
||||
|
||||
ngModule.vnComponent('vnSection', {
|
||||
controller: Section
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
let languages = {
|
||||
es: 'Español',
|
||||
en: 'English',
|
||||
ca: 'Català',
|
||||
pt: 'Português',
|
||||
fr: 'Français',
|
||||
nl: 'Nederlands',
|
||||
mn: 'Монгол хэл'
|
||||
};
|
||||
import config from '../../config.json';
|
||||
|
||||
class Controller {
|
||||
constructor($, $translate, vnConfig, vnAuth) {
|
||||
|
@ -25,7 +16,7 @@ class Controller {
|
|||
for (let code of $translate.getAvailableLanguageKeys()) {
|
||||
this.langs.push({
|
||||
code: code,
|
||||
name: languages[code] ? languages[code] : code
|
||||
name: config.languages[code] ? config.languages[code] : code
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"imagePath": "//verdnatura.es/vn-image-data",
|
||||
"langOptions": {
|
||||
"fallbackLang": "es",
|
||||
"langs": [
|
||||
"en",
|
||||
"es"
|
||||
],
|
||||
"langAliases": {
|
||||
"en_US": "en",
|
||||
"en_GB": "en",
|
||||
"es_ES": "es",
|
||||
"es_AR": "es"
|
||||
}
|
||||
},
|
||||
"languages": {
|
||||
"es": "Español",
|
||||
"en": "English",
|
||||
"ca": "Català",
|
||||
"pt": "Português",
|
||||
"fr": "Français",
|
||||
"nl": "Nederlands",
|
||||
"mn": "Монгол хэл"
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ Name: Nombre
|
|||
Preview: Vista previa
|
||||
Profile: Perfil
|
||||
Push on applications menu: Para abrir un módulo pulsa en el menú de aplicaciones
|
||||
Return to module index: Volver a la página principal del módulo
|
||||
Go to module index: Ir al índice del módulo
|
||||
What is new: Novedades de la versión
|
||||
Settings: Ajustes
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {ng} from 'core/vendor';
|
||||
import appConfig from './config.json';
|
||||
import 'core';
|
||||
|
||||
export const appName = 'salix';
|
||||
|
@ -8,6 +9,8 @@ export default ngModule;
|
|||
|
||||
run.$inject = ['$window', '$rootScope', 'vnAuth', 'vnApp', '$state'];
|
||||
export function run($window, $rootScope, vnAuth, vnApp, $state) {
|
||||
$rootScope.imagePath = appConfig.imagePath;
|
||||
|
||||
$window.validations = {};
|
||||
vnApp.name = appName;
|
||||
|
||||
|
@ -57,8 +60,22 @@ export function run($window, $rootScope, vnAuth, vnApp, $state) {
|
|||
}
|
||||
ngModule.run(run);
|
||||
|
||||
config.$inject = ['$translatePartialLoaderProvider', '$httpProvider', '$compileProvider'];
|
||||
export function config($translatePartialLoaderProvider, $httpProvider, $compileProvider) {
|
||||
config.$inject = ['$translateProvider', '$translatePartialLoaderProvider', '$httpProvider', '$compileProvider'];
|
||||
export function config($translateProvider, $translatePartialLoaderProvider, $httpProvider, $compileProvider) {
|
||||
const langOptions = appConfig.langOptions;
|
||||
$translateProvider
|
||||
.registerAvailableLanguageKeys(langOptions.langs, langOptions.langAliases)
|
||||
// TODO: Circular dependency due to vnInterceptor
|
||||
// .fallbackLanguage(langOptions.fallbackLang)
|
||||
.determinePreferredLanguage(() => {
|
||||
const locale = $translateProvider.resolveClientLocale();
|
||||
if (langOptions.langs.indexOf(locale) !== -1)
|
||||
return locale;
|
||||
if (langOptions.langAliases[locale])
|
||||
return langOptions.langAliases[locale];
|
||||
return fallbackLang;
|
||||
});
|
||||
|
||||
$translatePartialLoaderProvider.addPart(appName);
|
||||
$httpProvider.interceptors.push('vnInterceptor');
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
justify-content: center;
|
||||
|
||||
& > .product {
|
||||
flex: initial;
|
||||
box-sizing: border-box;
|
||||
padding: $spacing-sm;
|
||||
width: 448px;
|
||||
|
|
|
@ -131,5 +131,6 @@
|
|||
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
|
||||
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
||||
"This ticket is deleted": "Este ticket está eliminado",
|
||||
"A travel with this data already exists": "Ya existe un travel con estos datos"
|
||||
"A travel with this data already exists": "Ya existe un travel con estos datos",
|
||||
"AMOUNT_NOT_MATCH_GROUPING": "AMOUNT_NOT_MATCH_GROUPING"
|
||||
}
|
|
@ -7,19 +7,16 @@
|
|||
auto-save="true"
|
||||
on-save="$ctrl.onSave()">
|
||||
</vn-crud-model>
|
||||
|
||||
<vn-crud-model auto-load="true"
|
||||
url="ClaimDestinations"
|
||||
data="claimDestinations">
|
||||
</vn-crud-model>
|
||||
|
||||
<vn-card class="vn-mb-md vn-pa-lg vn-w-lg" style="text-align: right"
|
||||
ng-if="$ctrl.salesClaimed.length > 0">
|
||||
<vn-label-value label="Total claimed"
|
||||
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
||||
</vn-label-value>
|
||||
</vn-card>
|
||||
|
||||
<vn-card class="vn-pa-lg vn-w-lg">
|
||||
<section class="header">
|
||||
<vn-tool-bar class="vn-mb-md">
|
||||
|
@ -57,7 +54,6 @@
|
|||
on-change="$ctrl.save({isChargedToMana: value})">
|
||||
</vn-check>
|
||||
</section>
|
||||
|
||||
<vn-data-viewer model="model">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
|
@ -79,7 +75,7 @@
|
|||
vn-repeat-last on-last="$ctrl.focusLastInput()">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)"
|
||||
ng-click="descriptor.show($event, saleClaimed.sale.itemFk)"
|
||||
class="link">
|
||||
{{::saleClaimed.sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
|
@ -87,7 +83,7 @@
|
|||
<vn-td number>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showTicketDescriptor($event, saleClaimed.sale.ticketFk)">
|
||||
ng-click="ticketDescriptor.show($event, saleClaimed.sale.ticketFk)">
|
||||
{{::saleClaimed.sale.ticketFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
|
@ -121,7 +117,6 @@
|
|||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-data-viewer>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-button
|
||||
label="Regularize"
|
||||
|
@ -130,7 +125,6 @@
|
|||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</vn-card>
|
||||
|
||||
<vn-crud-model
|
||||
vn-id="lastTicketsModel"
|
||||
url="Tickets"
|
||||
|
@ -173,5 +167,5 @@
|
|||
vn-id="update-greuge"
|
||||
question="Insert greuges on client card"
|
||||
message="Do you want to insert greuges?"
|
||||
on-response="$ctrl.onUpdateGreugeResponse($response)">
|
||||
on-accept="$ctrl.onUpdateGreugeAccept()">
|
||||
</vn-confirm>
|
|
@ -41,18 +41,10 @@ export default class Controller extends Section {
|
|||
let query = `ClaimBeginnings/${this.$params.id}/importToNewRefundTicket`;
|
||||
return this.$http.post(query).then(() => {
|
||||
this.$.model.refresh();
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
});
|
||||
}
|
||||
|
||||
showTicketDescriptor(event, ticketFk) {
|
||||
this.$.ticketDescriptor.ticketFk = ticketFk;
|
||||
this.$.ticketDescriptor.parent = event.target;
|
||||
this.$.ticketDescriptor.show();
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
focusLastInput() {
|
||||
let inputs = document.querySelectorAll('#claimDestinationFk');
|
||||
inputs[inputs.length - 1].querySelector('input').focus();
|
||||
|
@ -84,8 +76,7 @@ export default class Controller extends Section {
|
|||
};
|
||||
this.$.lastTicketsModel.filter = filter;
|
||||
this.$.lastTicketsModel.refresh();
|
||||
this.$.lastTicketsPopover.parent = event.target;
|
||||
this.$.lastTicketsPopover.show();
|
||||
this.$.lastTicketsPopover.show(event);
|
||||
}
|
||||
|
||||
importTicketLines(ticketFk) {
|
||||
|
@ -93,7 +84,7 @@ export default class Controller extends Section {
|
|||
|
||||
let query = `ClaimEnds/importTicketSales`;
|
||||
this.$http.post(query, data).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
this.$.lastTicketsPopover.hide();
|
||||
this.$.model.refresh();
|
||||
});
|
||||
|
@ -105,7 +96,7 @@ export default class Controller extends Section {
|
|||
if (this.claim.responsibility >= Math.ceil(this.maxResponsibility) / 2)
|
||||
this.$.updateGreuge.show();
|
||||
else
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
|
||||
this.card.reload();
|
||||
});
|
||||
|
@ -130,46 +121,36 @@ export default class Controller extends Section {
|
|||
});
|
||||
}
|
||||
|
||||
onUpdateGreugeResponse(response) {
|
||||
if (response == 'accept') {
|
||||
const promises = [];
|
||||
promises.push(this.getGreugeTypeId());
|
||||
promises.push(this.getGreugeConfig());
|
||||
onUpdateGreugeAccept() {
|
||||
const promises = [];
|
||||
promises.push(this.getGreugeTypeId());
|
||||
promises.push(this.getGreugeConfig());
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
const data = {
|
||||
clientFk: this.claim.clientFk,
|
||||
description: this.$translate.instant('ClaimGreugeDescription', {
|
||||
claimId: this.claim.id
|
||||
}).toUpperCase(),
|
||||
amount: this.freightPickUpPrice,
|
||||
greugeTypeFk: this.greugeTypeFreightId,
|
||||
ticketFk: this.claim.ticketFk
|
||||
};
|
||||
return this.$http.post(`Greuges/`, data).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.vnApp.showMessage(this.$translate.instant('Greuge inserted'));
|
||||
});
|
||||
return Promise.all(promises).then(() => {
|
||||
const data = {
|
||||
clientFk: this.claim.clientFk,
|
||||
description: this.$t('ClaimGreugeDescription', {
|
||||
claimId: this.claim.id
|
||||
}).toUpperCase(),
|
||||
amount: this.freightPickUpPrice,
|
||||
greugeTypeFk: this.greugeTypeFreightId,
|
||||
ticketFk: this.claim.ticketFk
|
||||
};
|
||||
return this.$http.post(`Greuges`, data).then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
this.vnApp.showMessage(this.$t('Greuge inserted'));
|
||||
});
|
||||
} else
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
}
|
||||
|
||||
showDescriptor(event, itemFk) {
|
||||
this.$.descriptor.itemFk = itemFk;
|
||||
this.$.descriptor.parent = event.target;
|
||||
this.$.descriptor.show();
|
||||
});
|
||||
}
|
||||
|
||||
save(data) {
|
||||
const query = `Claims/${this.$params.id}/updateClaimAction`;
|
||||
this.$http.patch(query, data).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
});
|
||||
this.$http.patch(query, data)
|
||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
||||
}
|
||||
|
||||
onSave() {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,20 +6,15 @@ describe('claim', () => {
|
|||
let controller;
|
||||
let $httpBackend;
|
||||
let $state;
|
||||
let $httpParamSerializer;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($rootScope, $componentController, _$state_, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$scope = $rootScope.$new();
|
||||
beforeEach(angular.mock.inject(($componentController, _$state_, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$state = _$state_;
|
||||
$state.params.id = 1;
|
||||
|
||||
const $element = angular.element('<vn-claim-action></vn-claim-action>');
|
||||
controller = $componentController('vnClaimAction', {$element, $scope});
|
||||
controller = $componentController('vnClaimAction', {$element: null});
|
||||
controller.claim = {ticketFk: 1};
|
||||
controller.$.model = {refresh: () => {}};
|
||||
controller.$.addSales = {
|
||||
|
@ -67,8 +62,8 @@ describe('claim', () => {
|
|||
controller.importToNewRefundTicket();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
expect(controller.$.model.refresh).toHaveBeenCalled();
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -79,8 +74,8 @@ describe('claim', () => {
|
|||
|
||||
controller.showLastTickets({});
|
||||
|
||||
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalledWith();
|
||||
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalledWith();
|
||||
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalled();
|
||||
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -124,33 +119,21 @@ describe('claim', () => {
|
|||
controller.save(data);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onUpdateGreugeResponse()', () => {
|
||||
describe('onUpdateGreugeAccept()', () => {
|
||||
const greugeTypeId = 7;
|
||||
const freightPickUpPrice = 11;
|
||||
it('should do nothing', () => {
|
||||
jest.spyOn(controller.$http, 'post');
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
|
||||
controller.onUpdateGreugeResponse('cancel');
|
||||
|
||||
expect(controller.$http.post).not.toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).not.toHaveBeenCalledWith();
|
||||
expect(controller.vnApp.showSuccess).not.toHaveBeenCalledWith('Greuge inserted!');
|
||||
});
|
||||
|
||||
it('should make a query and get the greugeTypeId and greuge config', () => {
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
|
||||
const greugeTypeParams = $httpParamSerializer({filter: {where: {code: 'freightPickUp'}}});
|
||||
$httpBackend.expect('GET', `GreugeTypes/findOne?${greugeTypeParams}`).respond({id: greugeTypeId});
|
||||
$httpBackend.expect('GET', `GreugeConfigs/findOne`).respond({freightPickUpPrice});
|
||||
controller.onUpdateGreugeResponse('accept');
|
||||
$httpBackend.expectRoute('GET', `GreugeTypes/findOne`).respond({id: greugeTypeId});
|
||||
$httpBackend.expectGET(`GreugeConfigs/findOne`).respond({freightPickUpPrice});
|
||||
controller.onUpdateGreugeAccept();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.greugeTypeFreightId).toEqual(greugeTypeId);
|
||||
|
@ -181,7 +164,7 @@ describe('claim', () => {
|
|||
$httpBackend.expect('POST', `Greuges/`, data).respond(new Promise(resolve => {
|
||||
return resolve({id: freightPickUpPrice});
|
||||
}));
|
||||
controller.onUpdateGreugeResponse('accept').then(res => {
|
||||
controller.onUpdateGreugeAccept().then(res => {
|
||||
|
||||
}).catch(error => {
|
||||
|
||||
|
|
|
@ -1,62 +1,81 @@
|
|||
<div class="vn-descriptor">
|
||||
<div class="header">
|
||||
<a translate-attr="{title: 'Return to module index'}" ui-sref="claim.index">
|
||||
<vn-icon icon="chevron_left"></vn-icon>
|
||||
<vn-descriptor-content
|
||||
module="claim"
|
||||
description="$ctrl.claim.client.name">
|
||||
<slot-menu>
|
||||
<a class="vn-item"
|
||||
ui-sref="ticket.create({clientFk: $ctrl.client.id})"
|
||||
translate>
|
||||
Show Pickup order
|
||||
</a>
|
||||
<a translate-attr="{title: 'Preview'}" ui-sref="claim.card.summary({id: $ctrl.claim.id})">
|
||||
<vn-icon icon="desktop_windows"></vn-icon>
|
||||
</a>
|
||||
<vn-icon-menu
|
||||
vn-id="more-button"
|
||||
icon="more_vert"
|
||||
show-filter="false"
|
||||
value-field="callback"
|
||||
translate-fields="['name']"
|
||||
data="$ctrl.moreOptions"
|
||||
on-change="$ctrl.onMoreChange(value)"
|
||||
on-open="$ctrl.onMoreOpen()">
|
||||
</vn-icon-menu>
|
||||
</div>
|
||||
<div class="body">
|
||||
<vn-item
|
||||
ng-click="confirmPickupOrder.show()"
|
||||
translate>
|
||||
Send Pickup order
|
||||
</vn-item>
|
||||
<vn-item
|
||||
vn-acl="salesAssistant"
|
||||
vn-acl-action="remove"
|
||||
ng-click="confirmDeleteClaim.show()"
|
||||
name="deleteClaim"
|
||||
translate>
|
||||
Delete claim
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
<slot-body>
|
||||
<div class="attributes">
|
||||
<h5>{{$ctrl.claim.id}}</h5>
|
||||
<vn-label-value label="Client"
|
||||
value="{{::$ctrl.claim.client.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="State"
|
||||
<vn-label-value
|
||||
label="State"
|
||||
value="{{$ctrl.claim.claimState.description}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Created"
|
||||
value="{{$ctrl.claim.created | date: 'dd/MM/yyyy HH:mm'}}">
|
||||
<vn-label-value
|
||||
label="Created"
|
||||
value="{{$ctrl.claim.created | date: 'dd/MM/yyyy HH:mm'}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Salesperson"
|
||||
<vn-label-value
|
||||
label="Salesperson"
|
||||
value="{{$ctrl.claim.client.salesPerson.user.nickname}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Attended by"
|
||||
<vn-label-value
|
||||
label="Attended by"
|
||||
value="{{$ctrl.claim.worker.user.nickname}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Agency"
|
||||
value="{{$ctrl.claim.ticket.agencyMode.name}}">
|
||||
<vn-label-value
|
||||
label="Agency"
|
||||
value="{{$ctrl.claim.ticket.agencyMode.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Ticket"
|
||||
value="{{$ctrl.claim.ticketFk}}">
|
||||
<vn-label-value
|
||||
label="Ticket"
|
||||
value="{{$ctrl.claim.ticketFk}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
<vn-quick-links
|
||||
links="$ctrl.quicklinks">
|
||||
</vn-quick-links>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quicklinks">
|
||||
<div ng-transclude="btnOne">
|
||||
<vn-quick-link
|
||||
tooltip="Client ticket list"
|
||||
state="['client.card.summary', {id: $ctrl.claim.clientFk}]"
|
||||
icon="person">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnTwo">
|
||||
<vn-quick-link
|
||||
tooltip="Claimed ticket"
|
||||
state="['ticket.card.summary', {id: $ctrl.claim.ticketFk}]"
|
||||
icon="icon-ticket">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnThree"></div>
|
||||
</div>
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
<vn-confirm
|
||||
vn-id="confirm-pickup-order"
|
||||
on-response="$ctrl.sendPickupOrder($response)"
|
||||
vn-id="confirmPickupOrder"
|
||||
on-accept="$ctrl.sendPickupOrder()"
|
||||
question="Send Pickup order"
|
||||
message="Are you sure you want to send it?">
|
||||
</vn-confirm>
|
||||
<vn-confirm
|
||||
vn-id="confirm-delete-claim"
|
||||
on-response="$ctrl.deleteClaim($response)"
|
||||
vn-id="confirmDeleteClaim"
|
||||
on-accept="$ctrl.deleteClaim()"
|
||||
question="Delete claim"
|
||||
message="Are you sure you want to delete this claim?">
|
||||
</vn-confirm>
|
||||
|
||||
|
|
|
@ -1,112 +1,43 @@
|
|||
import ngModule from '../module';
|
||||
import Component from 'core/lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $, $httpParamSerializer) {
|
||||
super($element, $);
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
|
||||
this.moreOptions = [
|
||||
{callback: this.showPickupOrder, name: 'Show Pickup order'},
|
||||
{callback: this.confirmPickupOrder, name: 'Send Pickup order'},
|
||||
{callback: this.confirmDeleteClaim, name: 'Delete claim', acl: 'salesAssistant'}
|
||||
];
|
||||
}
|
||||
|
||||
onMoreOpen() {
|
||||
let options = this.moreOptions.filter(option => {
|
||||
const hasAclProperty = Object.hasOwnProperty.call(option, 'acl');
|
||||
|
||||
return !hasAclProperty || (hasAclProperty && this.aclService.hasAny([option.acl]));
|
||||
});
|
||||
this.$.moreButton.data = options;
|
||||
}
|
||||
|
||||
onMoreChange(callback) {
|
||||
callback.call(this);
|
||||
}
|
||||
import Descriptor from 'salix/components/descriptor';
|
||||
|
||||
class Controller extends Descriptor {
|
||||
get claim() {
|
||||
return this._claim;
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
set claim(value) {
|
||||
this._claim = value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
this._quicklinks = {
|
||||
btnOne: {
|
||||
icon: 'person',
|
||||
state: `client.card.summary({id: ${value.clientFk}})`,
|
||||
tooltip: 'Client card'
|
||||
},
|
||||
btnTwo: {
|
||||
icon: 'icon-ticket',
|
||||
state: `ticket.card.summary({id: ${this.claim.ticketFk}})`,
|
||||
tooltip: 'Claimed ticket'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
set quicklinks(value = {}) {
|
||||
this._quicklinks = Object.assign(value, this._quicklinks);
|
||||
}
|
||||
|
||||
get quicklinks() {
|
||||
return this._quicklinks;
|
||||
this.entity = value;
|
||||
}
|
||||
|
||||
showPickupOrder() {
|
||||
const params = {
|
||||
this.showReport('claim-pickup-order', {
|
||||
clientId: this.claim.clientFk,
|
||||
claimId: this.claim.id,
|
||||
authorization: this.vnToken.token
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
let url = `api/report/claim-pickup-order?${serializedParams}`;
|
||||
window.open(url);
|
||||
claimId: this.claim.id
|
||||
});
|
||||
}
|
||||
|
||||
confirmPickupOrder() {
|
||||
this.$.confirmPickupOrder.show();
|
||||
sendPickupOrder() {
|
||||
return this.sendEmail('claim-pickup-order', {
|
||||
recipient: this.claim.client.email,
|
||||
clientId: this.claim.clientFk,
|
||||
claimId: this.claim.id
|
||||
});
|
||||
}
|
||||
|
||||
sendPickupOrder(response) {
|
||||
if (response === 'accept') {
|
||||
const params = {
|
||||
recipient: this.claim.client.email,
|
||||
clientId: this.claim.clientFk,
|
||||
claimId: this.claim.id
|
||||
};
|
||||
this.$http.get(`email/claim-pickup-order`, {params}).then(
|
||||
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
confirmDeleteClaim() {
|
||||
this.$.confirmDeleteClaim.show();
|
||||
}
|
||||
|
||||
deleteClaim(response) {
|
||||
if (response === 'accept') {
|
||||
this.$http.delete(`Claims/${this.claim.id}`).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Claim deleted!'));
|
||||
deleteClaim() {
|
||||
return this.$http.delete(`Claims/${this.claim.id}`)
|
||||
.then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Claim deleted!'));
|
||||
this.$state.go('claim.index');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnClaimDescriptor', {
|
||||
ngModule.vnComponent('vnClaimDescriptor', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
claim: '<',
|
||||
tags: '<',
|
||||
quicklinks: '<'
|
||||
claim: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,96 +1,62 @@
|
|||
import './index.js';
|
||||
|
||||
describe('Item Component vnClaimDescriptor', () => {
|
||||
let $httpParamSerializer;
|
||||
let $httpBackend;
|
||||
let $element;
|
||||
let $scope;
|
||||
let controller;
|
||||
|
||||
const claim = {
|
||||
id: 2,
|
||||
clientFk: 101,
|
||||
client: {email: 'client@email'}
|
||||
};
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$scope = $rootScope.$new();
|
||||
|
||||
$element = angular.element('<vn-claim-descriptor></vn-claim-descriptor>');
|
||||
controller = $componentController('vnClaimDescriptor', {$element, $scope});
|
||||
controller.claim = {id: 2, clientFk: 101, client: {email: 'client@email'}};
|
||||
controller = $componentController('vnClaimDescriptor', {$element: null}, {claim});
|
||||
}));
|
||||
|
||||
describe('showPickupOrder()', () => {
|
||||
it('should open a new window showing a pickup order PDF document', () => {
|
||||
controller.showReport = jest.fn();
|
||||
|
||||
const params = {
|
||||
clientId: controller.claim.clientFk,
|
||||
claimId: controller.claim.id
|
||||
clientId: claim.clientFk,
|
||||
claimId: claim.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
let expectedPath = `api/report/claim-pickup-order?${serializedParams}`;
|
||||
jest.spyOn(window, 'open').mockReturnThis();
|
||||
controller.showPickupOrder();
|
||||
|
||||
expect(window.open).toHaveBeenCalledWith(expectedPath);
|
||||
expect(controller.showReport).toHaveBeenCalledWith('claim-pickup-order', params);
|
||||
});
|
||||
});
|
||||
|
||||
describe('confirmPickupOrder()', () => {
|
||||
it('should call confirmPickupOrder.show()', () => {
|
||||
controller.$.confirmPickupOrder = {
|
||||
show: jasmine.createSpy('show')
|
||||
};
|
||||
controller.claim = {id: 2};
|
||||
controller.confirmPickupOrder();
|
||||
|
||||
expect(controller.$.confirmPickupOrder.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sendPickupOrder(response)', () => {
|
||||
describe('sendPickupOrder()', () => {
|
||||
it('should make a query and call vnApp.showMessage() if the response is accept', () => {
|
||||
jest.spyOn(controller.vnApp, 'showMessage');
|
||||
jest.spyOn(controller, 'sendEmail');
|
||||
|
||||
const params = {
|
||||
recipient: 'client@email',
|
||||
clientId: controller.claim.clientFk,
|
||||
claimId: controller.claim.id
|
||||
recipient: claim.client.email,
|
||||
clientId: claim.clientFk,
|
||||
claimId: claim.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
controller.sendPickupOrder();
|
||||
|
||||
$httpBackend.when('GET', `email/claim-pickup-order?${serializedParams}`).respond();
|
||||
$httpBackend.expect('GET', `email/claim-pickup-order?${serializedParams}`).respond();
|
||||
controller.sendPickupOrder('accept');
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Notification sent!');
|
||||
expect(controller.sendEmail).toHaveBeenCalledWith('claim-pickup-order', params);
|
||||
});
|
||||
});
|
||||
|
||||
describe('confirmDeleteClaim()', () => {
|
||||
it('should call confirmDeleteClaim.show()', () => {
|
||||
controller.$.confirmDeleteClaim = {
|
||||
show: jasmine.createSpy('show')
|
||||
};
|
||||
controller.claim = {id: 2};
|
||||
controller.confirmDeleteClaim();
|
||||
|
||||
expect(controller.$.confirmDeleteClaim.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteClaime(response)', () => {
|
||||
describe('deleteClaim()', () => {
|
||||
it('should perform a query and call showSuccess if the response is accept', () => {
|
||||
let response = 'accept';
|
||||
controller.claim = {id: 2};
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
jest.spyOn(controller.$state, 'go');
|
||||
$httpBackend.when('DELETE', `Claims/2`).respond(200);
|
||||
$httpBackend.expect('DELETE', `Claims/2`);
|
||||
controller.deleteClaim(response);
|
||||
|
||||
$httpBackend.expectDELETE(`Claims/${claim.id}`).respond();
|
||||
controller.deleteClaim();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Claim deleted!');
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.index');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,9 +46,9 @@
|
|||
</vn-input-number>
|
||||
</vn-td>
|
||||
<vn-td expand title="{{::saleClaimed.sale.concept}}">
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)">
|
||||
<span
|
||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk)"
|
||||
class="link">
|
||||
{{::saleClaimed.sale.concept}}
|
||||
</span>
|
||||
</vn-td>
|
||||
|
@ -81,10 +81,10 @@
|
|||
</a>
|
||||
<!-- Add Lines Dialog -->
|
||||
<vn-dialog vn-id="add-sales" class="modal-form">
|
||||
<tpl-title>
|
||||
<span translate>Claimable sales from ticket</span> {{$ctrl.claim.ticketFk}}
|
||||
</tpl-title>
|
||||
<tpl-body>
|
||||
<vn-horizontal class="header vn-pa-md">
|
||||
<h5><span translate>Claimable sales from ticket</span> {{$ctrl.claim.ticketFk}}</h5>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-pa-md">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
|
@ -98,14 +98,17 @@
|
|||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="sale in $ctrl.salesToClaim" class="clickable" ng-click="$ctrl.addClaimedSale($index)">
|
||||
<vn-tr
|
||||
ng-repeat="sale in $ctrl.salesToClaim"
|
||||
ng-click="$ctrl.addClaimedSale($index)"
|
||||
class="clickable">
|
||||
<vn-td number>{{sale.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{sale.quantity}}</vn-td>
|
||||
<vn-td expand title="{{::sale.concept}}">
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showItemDescriptor($event, sale.itemFk)">
|
||||
{{sale.concept}}
|
||||
<span
|
||||
vn-click-stop="itemDescriptor.show($event, sale.itemFk)"
|
||||
class="link">
|
||||
{{sale.itemFk}} - {{sale.concept}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>{{sale.price | currency: 'EUR':2}}</vn-td>
|
||||
|
@ -120,7 +123,7 @@
|
|||
</tpl-body>
|
||||
</vn-dialog>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor">
|
||||
vn-id="itemDescriptor">
|
||||
</vn-item-descriptor-popover>
|
||||
<vn-popover
|
||||
class="edit"
|
||||
|
|
|
@ -109,13 +109,6 @@ class Controller extends Section {
|
|||
return total;
|
||||
}
|
||||
|
||||
showItemDescriptor(event, itemFk) {
|
||||
event.stopImmediatePropagation();
|
||||
this.$.descriptor.itemFk = itemFk;
|
||||
this.$.descriptor.parent = event.target;
|
||||
this.$.descriptor.show();
|
||||
}
|
||||
|
||||
showEditPopover(event, saleClaimed) {
|
||||
if (this.isEditable) {
|
||||
if (!this.aclService.hasAny(['salesAssistant']))
|
||||
|
|
|
@ -125,25 +125,6 @@ describe('claim', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('showItemDescriptor()', () => {
|
||||
it('should configure the descriptor then show it', () => {
|
||||
const itemId = 500;
|
||||
const event = {
|
||||
stopImmediatePropagation: () => {},
|
||||
target: 'the target element'
|
||||
};
|
||||
jest.spyOn(event, 'stopImmediatePropagation');
|
||||
jest.spyOn(controller.$.descriptor, 'show');
|
||||
|
||||
controller.showItemDescriptor(event, itemId);
|
||||
|
||||
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
|
||||
expect(controller.$.descriptor.itemFk).toEqual(itemId);
|
||||
expect(controller.$.descriptor.parent).toEqual(event.target);
|
||||
expect(controller.$.descriptor.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isClaimEditable()', () => {
|
||||
it('should check if the claim is editable', () => {
|
||||
controller.isClaimEditable();
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
<form name="form">
|
||||
<vn-horizontal ng-repeat="claimDevelopment in claimDevelopments">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
vn-focus
|
||||
label="Reason"
|
||||
ng-model="claimDevelopment.claimReasonFk"
|
||||
|
@ -52,7 +51,6 @@
|
|||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Result"
|
||||
ng-model="claimDevelopment.claimResultFk"
|
||||
data="claimResults"
|
||||
|
@ -61,7 +59,6 @@
|
|||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Responsible"
|
||||
ng-model="claimDevelopment.claimResponsibleFk"
|
||||
data="claimResponsibles"
|
||||
|
@ -69,8 +66,7 @@
|
|||
show-field="description"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
<vn-autocomplete
|
||||
ng-model="claimDevelopment.workerFk"
|
||||
url="Clients/activeWorkersWithRole"
|
||||
show-field="nickname"
|
||||
|
@ -81,7 +77,6 @@
|
|||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Redelivery"
|
||||
ng-model="claimDevelopment.claimRedeliveryFk"
|
||||
data="claimRedeliveries"
|
||||
|
@ -90,6 +85,7 @@
|
|||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
class="vn-my-md"
|
||||
vn-tooltip="Remove sale"
|
||||
icon="delete"
|
||||
|
|
|
@ -23,15 +23,17 @@
|
|||
ui-sref="claim.card.summary({id: claim.id})">
|
||||
<vn-td number>{{::claim.id}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span class="link" ng-click="$ctrl.showClientDescriptor($event, claim.clientFk)">
|
||||
<span
|
||||
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
|
||||
class="link">
|
||||
{{::claim.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center>{{::claim.created | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, claim.workerFk)">
|
||||
<span
|
||||
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
|
||||
class="link" >
|
||||
{{::claim.nickName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
|
@ -42,7 +44,7 @@
|
|||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
ng-click="$ctrl.preview($event, claim)"
|
||||
vn-click-stop="$ctrl.preview(claim)"
|
||||
vn-tooltip="Preview"
|
||||
icon="desktop_windows">
|
||||
</vn-icon-button>
|
||||
|
@ -56,10 +58,10 @@
|
|||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor"
|
||||
worker-fk="$ctrl.selectedWorker">
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-popup vn-id="dialog-summary-claim">
|
||||
<vn-claim-summary claim="$ctrl.claimSelected"></vn-claim-summary>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-claim-summary
|
||||
claim="$ctrl.claimSelected">
|
||||
</vn-claim-summary>
|
||||
</vn-popup>
|
||||
<vn-scroll-up></vn-scroll-up>
|
|
@ -13,31 +13,9 @@ export default class Controller extends Section {
|
|||
}
|
||||
}
|
||||
|
||||
showClientDescriptor(event, clientFk) {
|
||||
this.$.clientDescriptor.clientFk = clientFk;
|
||||
this.$.clientDescriptor.parent = event.target;
|
||||
this.$.clientDescriptor.show();
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.selectedWorker = workerFk;
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
preview(event, claim) {
|
||||
preview(claim) {
|
||||
this.claimSelected = claim;
|
||||
this.$.dialogSummaryClaim.show();
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
onDescriptorLoad() {
|
||||
this.$.popover.relocate();
|
||||
this.$.summary.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<vn-crud-model vn-id="model" auto-load="true"
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
auto-load="true"
|
||||
url="ClaimDms"
|
||||
link="{claimFk: $ctrl.$params.id}"
|
||||
limit="20"
|
||||
|
@ -17,7 +19,7 @@
|
|||
<section class="actions">
|
||||
<vn-button
|
||||
class="round"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
ng-click="confirm.show($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1"
|
||||
icon="delete">
|
||||
|
@ -25,19 +27,16 @@
|
|||
</section>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-confirm
|
||||
vn-id="confirm"
|
||||
message="This file will be deleted"
|
||||
question="Are you sure you want to continue?"
|
||||
on-response="$ctrl.deleteDms($response)">
|
||||
on-accept="$ctrl.deleteDms($data)">
|
||||
</vn-confirm>
|
||||
<vn-float-button fixed-bottom-right
|
||||
<vn-float-button
|
||||
icon="add"
|
||||
vn-tooltip="Select photo"
|
||||
vn-bind="+"
|
||||
ng-click="$ctrl.openUploadDialog()">
|
||||
ng-click="$ctrl.openUploadDialog()"
|
||||
fixed-bottom-right>
|
||||
</vn-float-button>
|
||||
|
|
|
@ -3,28 +3,13 @@ import Section from 'salix/components/section';
|
|||
import './style.scss';
|
||||
|
||||
class Controller extends Section {
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.workerFk = workerFk;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
showDeleteConfirm(index) {
|
||||
this.dmsIndex = index;
|
||||
this.$.confirm.show();
|
||||
}
|
||||
|
||||
deleteDms(response) {
|
||||
if (response === 'accept') {
|
||||
const dmsFk = this.photos[this.dmsIndex].dmsFk;
|
||||
const query = `claimDms/${dmsFk}/removeFile`;
|
||||
this.$http.post(query).then(() => {
|
||||
this.$.model.remove(this.dmsIndex);
|
||||
this.vnApp.showSuccess(this.$translate.instant('Photo deleted'));
|
||||
deleteDms(index) {
|
||||
const dmsFk = this.photos[index].dmsFk;
|
||||
return this.$http.post(`ClaimDms/${dmsFk}/removeFile`)
|
||||
.then(() => {
|
||||
this.$.model.remove(index);
|
||||
this.vnApp.showSuccess(this.$t('Photo deleted'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onDrop($event) {
|
||||
|
@ -36,10 +21,10 @@ class Controller extends Section {
|
|||
}
|
||||
|
||||
setDefaultParams() {
|
||||
const params = {filter: {
|
||||
const filter = {
|
||||
where: {code: 'claim'}
|
||||
}};
|
||||
return this.$http.get('DmsTypes/findOne', {params}).then(res => {
|
||||
};
|
||||
return this.$http.get('DmsTypes/findOne', {filter}).then(res => {
|
||||
const dmsTypeId = res.data && res.data.id;
|
||||
const companyId = this.vnConfig.companyFk;
|
||||
const warehouseId = this.vnConfig.warehouseFk;
|
||||
|
@ -50,7 +35,7 @@ class Controller extends Section {
|
|||
warehouseId: warehouseId,
|
||||
companyId: companyId,
|
||||
dmsTypeId: dmsTypeId,
|
||||
description: this.$translate.instant('FileDescription', {
|
||||
description: this.$t('FileDescription', {
|
||||
claimId: this.claim.id,
|
||||
clientId: this.claim.client.id,
|
||||
clientName: this.claim.client.name
|
||||
|
@ -91,7 +76,7 @@ class Controller extends Section {
|
|||
data: this.dms.files
|
||||
};
|
||||
this.$http(options).then(() => {
|
||||
this.vnApp.showSuccess(this.$translate.instant('Photo uploaded!'));
|
||||
this.vnApp.showSuccess(this.$t('Photo uploaded!'));
|
||||
this.$.model.refresh();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,16 +6,13 @@ describe('Claim', () => {
|
|||
let $scope;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
let $httpParamSerializer;
|
||||
|
||||
beforeEach(ngModule('claim'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
const $element = angular.element('<vn-claim-photos></vn-claim-photos>');
|
||||
controller = $componentController('vnClaimPhotos', {$element, $scope});
|
||||
controller = $componentController('vnClaimPhotos', {$element: null, $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.claim = {
|
||||
id: 1,
|
||||
|
@ -25,31 +22,25 @@ describe('Claim', () => {
|
|||
|
||||
describe('deleteDms()', () => {
|
||||
it('should make an HTTP Post query', () => {
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
jest.spyOn(controller.$.model, 'remove');
|
||||
controller.photos = [{dmsFk: 1}];
|
||||
controller.dmsIndex = dmsIndex;
|
||||
|
||||
$httpBackend.when('POST', `claimDms/${dmsId}/removeFile`).respond({});
|
||||
$httpBackend.expect('POST', `claimDms/${dmsId}/removeFile`);
|
||||
controller.deleteDms('accept');
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
controller.photos = [{dmsFk: 1}];
|
||||
|
||||
$httpBackend.expectPOST(`ClaimDms/${dmsId}/removeFile`).respond();
|
||||
controller.deleteDms(dmsIndex);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Photo deleted');
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultParams()', () => {
|
||||
it('should make an HTTP GET query, then set all dms properties', () => {
|
||||
const params = {filter: {
|
||||
where: {code: 'claim'}
|
||||
}};
|
||||
let serializedParams = $httpParamSerializer(params);
|
||||
$httpBackend.when('GET', `DmsTypes/findOne?${serializedParams}`).respond({});
|
||||
$httpBackend.expect('GET', `DmsTypes/findOne?${serializedParams}`);
|
||||
$httpBackend.expectRoute('GET', `DmsTypes/findOne`).respond({});
|
||||
controller.setDefaultParams();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
@ -67,13 +58,12 @@ describe('Claim', () => {
|
|||
controller.dmsIndex = dmsIndex;
|
||||
controller.dms = {files: []};
|
||||
|
||||
$httpBackend.when('POST', `claims/${claimId}/uploadFile`).respond({});
|
||||
$httpBackend.expect('POST', `claims/${claimId}/uploadFile`);
|
||||
$httpBackend.expectPOST(`claims/${claimId}/uploadFile`).respond({});
|
||||
controller.create();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Photo uploaded!');
|
||||
expect(controller.$.model.refresh).toHaveBeenCalled();
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,16 +6,20 @@
|
|||
<h5>{{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}}</h5>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-label-value label="Created"
|
||||
<vn-label-value
|
||||
label="Created"
|
||||
value="{{$ctrl.summary.claim.created | date: 'dd/MM/yyyy'}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="State"
|
||||
<vn-label-value
|
||||
label="State"
|
||||
value="{{$ctrl.summary.claim.claimState.description}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Salesperson"
|
||||
<vn-label-value
|
||||
label="Salesperson"
|
||||
value="{{$ctrl.summary.claim.client.salesPerson.user.nickname}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Attended by"
|
||||
<vn-label-value
|
||||
label="Attended by"
|
||||
value="{{$ctrl.summary.claim.worker.user.nickname}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
|
@ -61,7 +65,7 @@
|
|||
<vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale)"
|
||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
|
||||
class="link">
|
||||
{{::saleClaimed.sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
|
@ -113,7 +117,7 @@
|
|||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, development.workerFk)">
|
||||
ng-click="workerDescriptor.show($event, development.workerFk)">
|
||||
{{::development.worker.user.nickname}}
|
||||
</span>
|
||||
</vn-td>
|
||||
|
@ -144,14 +148,14 @@
|
|||
<vn-tr ng-repeat="action in $ctrl.summary.actions">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showItemDescriptor($event, action.sale.itemFk)"
|
||||
ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
|
||||
class="link">
|
||||
{{::action.sale.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showTicketDescriptor($event, action.sale.ticket.id)"
|
||||
ng-click="ticketDescriptor.show($event, action.sale.ticket.id)"
|
||||
class="link">
|
||||
{{::action.sale.ticket.id | zeroFill:6}}
|
||||
</span>
|
||||
|
@ -177,8 +181,7 @@
|
|||
vn-id="itemDescriptor">
|
||||
</vn-item-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor"
|
||||
worker-fk="$ctrl.selectedWorker">
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticketDescriptor">
|
||||
|
|
|
@ -32,24 +32,6 @@ class Controller extends Section {
|
|||
this.summary = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
showItemDescriptor(event, sale) {
|
||||
this.$.itemDescriptor.itemFk = sale.itemFk;
|
||||
this.$.itemDescriptor.parent = event.target;
|
||||
this.$.itemDescriptor.show();
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
this.selectedWorker = workerFk;
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
showTicketDescriptor(event, ticketId) {
|
||||
this.$.ticketDescriptor.ticketFk = ticketId;
|
||||
this.$.ticketDescriptor.parent = event.target;
|
||||
this.$.ticketDescriptor.show();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnClaimSummary', {
|
||||
|
|
|
@ -150,9 +150,9 @@
|
|||
<!-- Create custom agent dialog -->
|
||||
<vn-dialog class="edit"
|
||||
vn-id="customAgent"
|
||||
on-accept="$ctrl.onCustomAgentAccept()">
|
||||
on-accept="$ctrl.onCustomAgentAccept()"
|
||||
message="New customs agent">
|
||||
<tpl-body>
|
||||
<h5 class="vn-py-sm" translate>New customs agent</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one vn-focus
|
||||
label="NIF"
|
||||
|
|
|
@ -198,9 +198,9 @@
|
|||
<!-- Create custom agent dialog -->
|
||||
<vn-dialog class="edit"
|
||||
vn-id="customAgent"
|
||||
on-accept="$ctrl.onCustomAgentAccept()">
|
||||
on-accept="$ctrl.onCustomAgentAccept()"
|
||||
message="New customs agent">
|
||||
<tpl-body>
|
||||
<h5 class="vn-py-sm" translate>New customs agent</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one vn-focus
|
||||
label="NIF"
|
||||
|
|
|
@ -1,44 +1,38 @@
|
|||
<div>
|
||||
<tpl-body>
|
||||
<h6 translate>New payment</h6>
|
||||
<div class="vn-pa-md">
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Date"
|
||||
ng-model="$ctrl.receipt.payed">
|
||||
</vn-date-picker>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="Companies"
|
||||
label="Company"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.receipt.companyFk">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="Banks"
|
||||
label="Bank"
|
||||
show-field="bank"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.receipt.bankFk">
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
vn-focus
|
||||
label="Amount"
|
||||
ng-model="$ctrl.receipt.amountPaid"
|
||||
step="0.01"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate vn-focus>Accept</button>
|
||||
</tpl-buttons>
|
||||
</div>
|
||||
<tpl-title translate>
|
||||
New payment
|
||||
</tpl-title>
|
||||
<tpl-body>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
label="Date"
|
||||
ng-model="$ctrl.receipt.payed">
|
||||
</vn-date-picker>
|
||||
<vn-autocomplete
|
||||
url="Companies"
|
||||
label="Company"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.receipt.companyFk">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
url="Banks"
|
||||
label="Bank"
|
||||
show-field="bank"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.receipt.bankFk">
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
vn-focus
|
||||
label="Amount"
|
||||
ng-model="$ctrl.receipt.amountPaid"
|
||||
step="0.01"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate vn-focus>Accept</button>
|
||||
</tpl-buttons>
|
|
@ -1,11 +1,9 @@
|
|||
import ngModule from '../../module';
|
||||
import Dialog from 'core/components/dialog';
|
||||
import template from './index.html';
|
||||
|
||||
class Controller extends Dialog {
|
||||
constructor($element, $, $transclude) {
|
||||
super($element, $, $transclude);
|
||||
this.fillSlots(template);
|
||||
|
||||
this.receipt = {
|
||||
payed: new Date(),
|
||||
|
@ -76,8 +74,8 @@ class Controller extends Dialog {
|
|||
}
|
||||
|
||||
ngModule.vnComponent('vnClientBalanceCreate', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: Controller,
|
||||
transclude: true,
|
||||
bindings: {
|
||||
payed: '<?',
|
||||
bankFk: '<?',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="receipts/filter"
|
||||
url="Receipts/filter"
|
||||
limit="20"
|
||||
data="$ctrl.balances">
|
||||
</vn-crud-model>
|
||||
|
@ -66,19 +66,26 @@
|
|||
</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, balance.workerFk)">
|
||||
vn-click-stop="workerDescriptor.show($event, balance.workerFk)"
|
||||
class="link">
|
||||
{{::balance.userNickname}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
title="{{balance.isInvoice ? 'BILL' : balance.ref | translate: {ref: balance.ref} }}"
|
||||
ng-class="{'link': balance.isInvoice}"
|
||||
ng-click="$ctrl.showInvoiceOutDescriptor($event, balance)"
|
||||
ng-show="balance.ref">
|
||||
{{balance.isInvoice ? 'BILL' : balance.ref | translate: {ref: balance.ref} }}
|
||||
</span>
|
||||
<div ng-show="::balance.ref">
|
||||
<span
|
||||
ng-if="balance.isInvoice"
|
||||
title="{{'BILL' | translate: {ref: balance.ref} }}"
|
||||
vn-click-stop="invoiceOutDescriptor.show($event, balance)"
|
||||
ng-class="link">
|
||||
{{'BILL' | translate: {ref: balance.ref} }}
|
||||
</span>
|
||||
<span
|
||||
ng-if="!balance.isInvoice"
|
||||
title="{{::balance.ref}}">
|
||||
{{::balance.ref}}
|
||||
</span>
|
||||
</div>
|
||||
</vn-td>
|
||||
<vn-td number>{{::balance.bankFk}}</vn-td>
|
||||
<vn-td number expand>{{::balance.debit | currency: 'EUR':2}}</vn-td>
|
||||
|
@ -121,10 +128,8 @@
|
|||
company-fk="$ctrl.companyId">
|
||||
</vn-client-balance-create>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor"
|
||||
worker-fk="$ctrl.selectedWorker">
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-invoice-out-descriptor-popover
|
||||
vn-id="invoiceOutDescriptor"
|
||||
invoice-out-id="$ctrl.selectedInvoiceOut">
|
||||
vn-id="invoiceOutDescriptor">
|
||||
</vn-invoice-out-descriptor-popover>
|
|
@ -72,29 +72,6 @@ class Controller extends Section {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
if (event.defaultPrevented) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.selectedWorker = workerFk;
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
showInvoiceOutDescriptor(event, balance) {
|
||||
if (!balance.isInvoice) return;
|
||||
if (event.defaultPrevented) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.selectedInvoiceOut = balance.id;
|
||||
this.$.invoiceOutDescriptor.parent = event.target;
|
||||
this.$.invoiceOutDescriptor.show();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
|
|
@ -98,9 +98,9 @@
|
|||
<!-- Create bank entity dialog -->
|
||||
<vn-dialog class="edit"
|
||||
vn-id="bankEntityDialog"
|
||||
on-accept="$ctrl.onBankEntityAccept()">
|
||||
on-accept="$ctrl.onBankEntityAccept()"
|
||||
message="New bank entity">
|
||||
<tpl-body>
|
||||
<h5 class="vn-py-sm" translate>New bank entity</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
<vn-popover vn-id="popover">
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.client == null"
|
||||
style="padding: 1em;"
|
||||
enable="true">
|
||||
</vn-spinner>
|
||||
<vn-client-descriptor
|
||||
ng-if="$ctrl.client"
|
||||
client="$ctrl.client"
|
||||
quicklinks="$ctrl.quicklinks">
|
||||
</vn-client-descriptor>
|
||||
</vn-popover>
|
||||
<slot-descriptor>
|
||||
<vn-client-descriptor></vn-client-descriptor>
|
||||
</slot-descriptor>
|
|
@ -1,67 +1,9 @@
|
|||
import ngModule from '../module';
|
||||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
import DescriptorPopover from 'salix/components/descriptor-popover';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.client = null;
|
||||
this._quicklinks = {};
|
||||
}
|
||||
class Controller extends DescriptorPopover {}
|
||||
|
||||
set clientFk(id) {
|
||||
if (id == this._clientFk) return;
|
||||
|
||||
this._clientFk = id;
|
||||
this.client = null;
|
||||
this.getCard();
|
||||
}
|
||||
|
||||
set client(value) {
|
||||
this._client = value;
|
||||
this.$timeout(() => this.$.popover.relocate());
|
||||
}
|
||||
|
||||
get client() {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
get quicklinks() {
|
||||
return this._quicklinks;
|
||||
}
|
||||
|
||||
set quicklinks(value = {}) {
|
||||
Object.keys(value).forEach(key => {
|
||||
this._quicklinks[key] = value[key];
|
||||
});
|
||||
}
|
||||
|
||||
show() {
|
||||
this.$.popover.parent = this.parent;
|
||||
this.$.popover.show();
|
||||
}
|
||||
|
||||
getCard() {
|
||||
if (this.canceler)
|
||||
this.canceler.resolve();
|
||||
|
||||
this.canceler = this.$q.defer();
|
||||
|
||||
let options = {timeout: this.canceler.promise};
|
||||
this.$http.get(`Clients/${this._clientFk}/getCard`, options).then(
|
||||
response => {
|
||||
this.client = response.data;
|
||||
this.canceler = null;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnClientDescriptorPopover', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
clientFk: '<',
|
||||
quicklinks: '<'
|
||||
}
|
||||
ngModule.vnComponent('vnClientDescriptorPopover', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
import './index';
|
||||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientDescriptorPopover', () => {
|
||||
let $httpBackend;
|
||||
let $scope;
|
||||
let controller;
|
||||
let $element;
|
||||
let $timeout;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$timeout_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$timeout = _$timeout_;
|
||||
$element = angular.element(`<div></div>`);
|
||||
$scope = $rootScope.$new();
|
||||
$scope.popover = {relocate: () => {}, show: () => {}};
|
||||
controller = $componentController('vnClientDescriptorPopover', {$scope, $element});
|
||||
}));
|
||||
|
||||
describe('clientFk()', () => {
|
||||
it(`should not apply any changes if the received id is the same stored in _clientFk`, () => {
|
||||
controller.client = 'I exist!';
|
||||
controller._clientFk = 1;
|
||||
jest.spyOn(controller, 'getCard');
|
||||
controller.clientFk = 1;
|
||||
|
||||
expect(controller.client).toEqual('I exist!');
|
||||
expect(controller._clientFk).toEqual(1);
|
||||
expect(controller.getCard).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it(`should set the received id into _clientFk, set the client to null and then call getCard()`, () => {
|
||||
controller.client = `Please don't`;
|
||||
controller._clientFk = 1;
|
||||
jest.spyOn(controller, 'getCard');
|
||||
controller.clientFk = 999;
|
||||
|
||||
expect(controller.client).toBeNull();
|
||||
expect(controller._clientFk).toEqual(999);
|
||||
expect(controller.getCard).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('client()', () => {
|
||||
it(`should save the client into _client and then call relocate()`, () => {
|
||||
jest.spyOn(controller.$.popover, 'relocate');
|
||||
controller.client = `i'm the client!`;
|
||||
$timeout.flush();
|
||||
|
||||
expect(controller._client).toEqual(`i'm the client!`);
|
||||
expect(controller.$.popover.relocate).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('show()', () => {
|
||||
it(`should call the show()`, () => {
|
||||
jest.spyOn(controller.$.popover, 'show');
|
||||
controller.show();
|
||||
|
||||
expect(controller.$.popover.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCard()', () => {
|
||||
it(`should perform a get query to store the client data into the controller`, () => {
|
||||
controller.clientFk = 1;
|
||||
controller.canceler = null;
|
||||
let response = {};
|
||||
$httpBackend.when('GET', `Clients/${controller._clientFk}/getCard`).respond(response);
|
||||
$httpBackend.expect('GET', `Clients/${controller._clientFk}/getCard`);
|
||||
controller.getCard();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.client).toEqual(response);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
vn-client-descriptor-popover {
|
||||
vn-client-descriptor {
|
||||
display: block;
|
||||
width: 256px;
|
||||
& > vn-card{
|
||||
margin: 0!important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +1,46 @@
|
|||
<div class="vn-descriptor">
|
||||
<div class="header">
|
||||
<a translate-attr="{title: 'Return to module index'}" ui-sref="client.index">
|
||||
<vn-icon icon="chevron_left"></vn-icon>
|
||||
<vn-descriptor-content
|
||||
module="client"
|
||||
description="$ctrl.client.name">
|
||||
<slot-menu>
|
||||
<a class="vn-item"
|
||||
ui-sref="ticket.create({clientFk: $ctrl.client.id})"
|
||||
name="simpleTicket"
|
||||
translate>
|
||||
Simple ticket
|
||||
</a>
|
||||
<a translate-attr="{title: 'Preview'}" ui-sref="client.card.summary({id: $ctrl.client.id})">
|
||||
<vn-icon icon="desktop_windows"></vn-icon>
|
||||
</a>
|
||||
<vn-icon-menu
|
||||
vn-id="more-button"
|
||||
icon="more_vert"
|
||||
show-filter="false"
|
||||
value-field="callback"
|
||||
translate-fields="['name']"
|
||||
data="$ctrl.moreOptions"
|
||||
on-change="$ctrl.onMoreChange(value)"
|
||||
on-open="$ctrl.onMoreOpen()">
|
||||
</vn-icon-menu>
|
||||
</div>
|
||||
<div class="body">
|
||||
<vn-item
|
||||
ng-click="$ctrl.showSMSDialog()"
|
||||
translate>
|
||||
Send SMS
|
||||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="consumerReportDialog.show()"
|
||||
translate>
|
||||
Send consumer report
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
<slot-body>
|
||||
<div class="attributes">
|
||||
<h5>{{$ctrl.client.name}}</h5>
|
||||
<vn-label-value label="Id"
|
||||
value="{{$ctrl.client.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Phone"
|
||||
<vn-label-value
|
||||
label="Phone"
|
||||
value="{{$ctrl.client.phone | phone}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Credit"
|
||||
<vn-label-value
|
||||
label="Credit"
|
||||
value="{{$ctrl.client.credit | currency: 'EUR': 2}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Secured credit"
|
||||
<vn-label-value
|
||||
label="Secured credit"
|
||||
value="{{$ctrl.client.creditInsurance | currency: 'EUR': 2}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Risk"
|
||||
<vn-label-value
|
||||
label="Risk"
|
||||
value="{{$ctrl.client.debt | currency: 'EUR':2}}"
|
||||
ng-class="{alert: $ctrl.client.debt > $ctrl.client.credit}"
|
||||
info="Invoices minus payments plus orders not yet invoiced">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Sales person"
|
||||
<vn-label-value
|
||||
label="Sales person"
|
||||
value="{{$ctrl.client.salesPerson.user.nickname}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
|
@ -68,36 +71,48 @@
|
|||
ng-class="{bright: $ctrl.client.isTaxDataChecked == false}">
|
||||
</vn-icon>
|
||||
</div>
|
||||
<vn-quick-links
|
||||
links="$ctrl.quicklinks">
|
||||
</vn-quick-links>
|
||||
</div>
|
||||
</div>
|
||||
<!-- SMS Dialog -->
|
||||
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
|
||||
<!-- SMS Dialog -->
|
||||
<div class="quicklinks">
|
||||
<div ng-transclude="btnOne">
|
||||
<vn-quick-link
|
||||
tooltip="Client ticket list"
|
||||
state="['ticket.index', {q: $ctrl.filter}]"
|
||||
icon="icon-ticket">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnTwo">
|
||||
<vn-quick-link
|
||||
tooltip="New order"
|
||||
state="['order.create', {clientFk: $ctrl.id}]"
|
||||
icon="icon-basketadd">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnThree">
|
||||
</div>
|
||||
</div>
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
<vn-client-sms
|
||||
vn-id="sms"
|
||||
sms="$ctrl.newSMS">
|
||||
</vn-client-sms>
|
||||
<vn-dialog
|
||||
vn-id="consumerReportDialog"
|
||||
on-response="$ctrl.sendConsumerReport($response)">
|
||||
on-accept="$ctrl.onConsumerReportAccept()"
|
||||
message="Send consumer report">
|
||||
<tpl-body>
|
||||
<div>
|
||||
<h5 style="text-align: center">
|
||||
<span translate>Send consumer report</span>
|
||||
</h5>
|
||||
<vn-date-picker
|
||||
vn-id="from"
|
||||
vn-one
|
||||
ng-model="$ctrl.from"
|
||||
label="From date"
|
||||
vn-focus>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-id="to"
|
||||
vn-one
|
||||
ng-model="$ctrl.to"
|
||||
label="To date">
|
||||
<vn-date-picker
|
||||
vn-id="from"
|
||||
vn-one
|
||||
ng-model="$ctrl.from"
|
||||
label="From date"
|
||||
vn-focus>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-id="to"
|
||||
vn-one
|
||||
ng-model="$ctrl.to"
|
||||
label="To date">
|
||||
</vn-date-picker>
|
||||
</div>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
|
|
|
@ -1,97 +1,58 @@
|
|||
import ngModule from '../module';
|
||||
import Component from 'core/lib/component';
|
||||
import Descriptor from 'salix/components/descriptor';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $, $httpParamSerializer) {
|
||||
super($element, $);
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
|
||||
this.moreOptions = [
|
||||
{name: 'Simple ticket', callback: this.newTicket},
|
||||
{name: 'Send SMS', callback: this.showSMSDialog},
|
||||
{name: 'Send consumer report', callback: this.showConsumerReportDialog}
|
||||
];
|
||||
class Controller extends Descriptor {
|
||||
get entity() {
|
||||
return super.entity;
|
||||
}
|
||||
|
||||
onMoreChange(callback) {
|
||||
callback.call(this);
|
||||
}
|
||||
|
||||
get client() {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
set client(value) {
|
||||
this._client = value;
|
||||
if (!value) return;
|
||||
set entity(value) {
|
||||
super.entity = value;
|
||||
|
||||
if (this.$params.sendSMS)
|
||||
this.showSMSDialog();
|
||||
|
||||
this._quicklinks = {
|
||||
btnOne: {
|
||||
icon: 'icon-ticket',
|
||||
state: `ticket.index({q: '{"clientFk": ${value.id}}'})`,
|
||||
tooltip: 'Client ticket list'
|
||||
},
|
||||
btnTwo: {
|
||||
icon: 'icon-basketadd',
|
||||
state: `order.create({clientFk: ${value.id}})`,
|
||||
tooltip: 'New order'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
set quicklinks(value = {}) {
|
||||
this._quicklinks = Object.assign(value, this._quicklinks);
|
||||
get client() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
get quicklinks() {
|
||||
return this._quicklinks;
|
||||
set client(value) {
|
||||
this.entity = value;
|
||||
}
|
||||
|
||||
newTicket() {
|
||||
this.$state.go('ticket.create', {clientFk: this.client.id});
|
||||
get filter() {
|
||||
return JSON.stringify({clientFk: this.id});
|
||||
}
|
||||
|
||||
loadData() {
|
||||
return this.getData(`Clients/${this.id}/getCard`)
|
||||
.then(res => this.entity = res.data);
|
||||
}
|
||||
|
||||
showSMSDialog() {
|
||||
const client = this.client;
|
||||
const phone = this.$params.phone || client.mobile || client.phone;
|
||||
const message = this.$params.message || '';
|
||||
const client = this.client || {};
|
||||
this.newSMS = {
|
||||
destinationFk: client.id,
|
||||
destination: phone,
|
||||
message: message
|
||||
destinationFk: this.id,
|
||||
destination: this.$params.phone || client.mobile || client.phone,
|
||||
message: this.$params.message || ''
|
||||
};
|
||||
this.$.sms.open();
|
||||
}
|
||||
|
||||
showConsumerReportDialog() {
|
||||
this.$.consumerReportDialog.show();
|
||||
}
|
||||
|
||||
sendConsumerReport(response) {
|
||||
if (response === 'accept') {
|
||||
const params = {
|
||||
authorization: this.vnToken.token,
|
||||
clientId: this.client.id,
|
||||
from: this.from,
|
||||
to: this.to,
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
const url = `api/report/campaign-metrics?${serializedParams}`;
|
||||
window.open(url);
|
||||
}
|
||||
onConsumerReportAccept() {
|
||||
this.showReport('campaign-metrics', {
|
||||
clientId: this.id,
|
||||
from: this.from,
|
||||
to: this.to,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnClientDescriptor', {
|
||||
ngModule.vnComponent('vnClientDescriptor', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
client: '<',
|
||||
quicklinks: '<'
|
||||
},
|
||||
controller: Controller
|
||||
client: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import './index';
|
||||
|
||||
describe('vnClientDescriptor', () => {
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnClientDescriptor', {$element: null});
|
||||
}));
|
||||
|
||||
describe('loadData()', () => {
|
||||
it(`should perform a get query to store the client data into the controller`, () => {
|
||||
const id = 1;
|
||||
const response = 'foo';
|
||||
|
||||
$httpBackend.expectGET(`Clients/${id}/getCard`).respond(response);
|
||||
controller.id = id;
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.client).toEqual(response);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -62,7 +62,7 @@
|
|||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
|
||||
ng-click="workerDescriptor.show($event, document.dms.workerFk)">
|
||||
{{::document.dms.worker.user.nickname | dashIfEmpty}}
|
||||
</span></vn-td>
|
||||
<vn-td>
|
||||
|
@ -86,7 +86,7 @@
|
|||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="delete"
|
||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
||||
ng-click="confirm.show($index)"
|
||||
title="{{'Remove file' | translate}}"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
|
@ -109,5 +109,5 @@
|
|||
vn-id="confirm"
|
||||
message="This file will be deleted"
|
||||
question="Are you sure you want to continue?"
|
||||
on-response="$ctrl.deleteDms($response)">
|
||||
on-accept="$ctrl.deleteDms($data)">
|
||||
</vn-confirm>
|
|
@ -24,8 +24,7 @@ class Controller extends Section {
|
|||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
|
@ -42,28 +41,13 @@ class Controller extends Section {
|
|||
};
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.workerFk = workerFk;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
|
||||
showDeleteConfirm(index) {
|
||||
this.dmsIndex = index;
|
||||
this.$.confirm.show();
|
||||
}
|
||||
|
||||
deleteDms(response) {
|
||||
if (response === 'accept') {
|
||||
const dmsFk = this.clientDms[this.dmsIndex].dmsFk;
|
||||
const query = `clientDms/${dmsFk}/removeFile`;
|
||||
this.$http.post(query).then(() => {
|
||||
this.$.model.remove(this.dmsIndex);
|
||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||
deleteDms(index) {
|
||||
const dmsFk = this.clientDms[index].dmsFk;
|
||||
return this.$http.post(`ClientDms/${dmsFk}/removeFile`)
|
||||
.then(() => {
|
||||
this.$.model.remove(index);
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,27 +12,25 @@ describe('Client', () => {
|
|||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
const $element = angular.element('<vn-client-dms-index></vn-client-dms-index>');
|
||||
controller = $componentController('vnClientDmsIndex', {$element, $scope});
|
||||
controller = $componentController('vnClientDmsIndex', {$element: null, $scope});
|
||||
controller.$.model = crudModel;
|
||||
}));
|
||||
|
||||
describe('deleteDms()', () => {
|
||||
it('should make an HTTP Post query', () => {
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
jest.spyOn(controller.$.model, 'remove');
|
||||
controller.clientDms = [{dmsFk: 1}];
|
||||
controller.dmsIndex = dmsIndex;
|
||||
|
||||
$httpBackend.when('POST', `clientDms/${dmsId}/removeFile`).respond({});
|
||||
$httpBackend.expect('POST', `clientDms/${dmsId}/removeFile`);
|
||||
controller.deleteDms('accept');
|
||||
const dmsId = 1;
|
||||
const dmsIndex = 0;
|
||||
controller.clientDms = [{dmsFk: 1}];
|
||||
|
||||
$httpBackend.expectPOST(`ClientDms/${dmsId}/removeFile`).respond();
|
||||
controller.deleteDms(dmsIndex);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<vn-dialog class="edit"
|
||||
vn-id="postcodeDialog"
|
||||
on-open="$ctrl.onOpen()"
|
||||
on-accept="$ctrl.onAccept()">
|
||||
on-accept="$ctrl.onAccept()"
|
||||
message="New postcode">
|
||||
<tpl-body>
|
||||
<h5 class="vn-py-sm" translate>New postcode</h5>
|
||||
<p translate>Please, ensure you put the correct data!</p>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"module": "client",
|
||||
"name": "Clients",
|
||||
"icon": "icon-person",
|
||||
"icon": "person",
|
||||
"validations" : true,
|
||||
"dependencies": ["worker", "invoiceOut"],
|
||||
"menus": {
|
||||
"main": [
|
||||
{"state": "client.index", "icon": "icon-person"}
|
||||
{"state": "client.index", "icon": "person"}
|
||||
],
|
||||
"card": [
|
||||
{"state": "client.card.basicData", "icon": "settings"},
|
||||
|
|
|
@ -29,9 +29,10 @@
|
|||
{{::sample.type.description}}
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span class="link"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, sample.worker.id)">
|
||||
{{::sample.worker.user.nickname}}
|
||||
<span
|
||||
ng-click="workerDescriptor.show($event, sample.worker.id)"
|
||||
class="link">
|
||||
{{::sample.worker.user.nickname}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::sample.company.code}}</vn-td>
|
||||
|
@ -41,8 +42,7 @@
|
|||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor"
|
||||
worker-fk="$ctrl.selectedWorker">
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<a
|
||||
ui-sref="client.card.sample.create"
|
||||
|
|
|
@ -11,8 +11,7 @@ class Controller extends Section {
|
|||
scope: {
|
||||
fields: ['code', 'description']
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
|
@ -23,8 +22,7 @@ class Controller extends Section {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
relation: 'company',
|
||||
scope: {
|
||||
fields: ['code']
|
||||
|
@ -33,20 +31,8 @@ class Controller extends Section {
|
|||
]
|
||||
};
|
||||
}
|
||||
showWorkerDescriptor(event, workerFk) {
|
||||
if (event.defaultPrevented) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
this.selectedWorker = workerFk;
|
||||
this.$.workerDescriptor.parent = event.target;
|
||||
this.$.workerDescriptor.show();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.component('vnClientSampleIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
|
|
|
@ -1,30 +1,18 @@
|
|||
<div class="vn-descriptor">
|
||||
<div class="header">
|
||||
<a translate-attr="{title: 'Return to module index'}" ui-sref="entry.index">
|
||||
<vn-icon icon="chevron_left"></vn-icon>
|
||||
</a>
|
||||
<a translate-attr="{title: 'Preview'}" ui-sref="entry.card.summary({id: $ctrl.entry.id})">
|
||||
<vn-icon icon="desktop_windows"></vn-icon>
|
||||
</a>
|
||||
<vn-icon-menu
|
||||
vn-id="more-button"
|
||||
icon="more_vert"
|
||||
show-filter="false"
|
||||
value-field="callback"
|
||||
translate-fields="['name']"
|
||||
data="$ctrl.moreOptions"
|
||||
on-change="$ctrl.onMoreChange(value)"
|
||||
on-open="$ctrl.onMoreOpen()">
|
||||
</vn-icon-menu>
|
||||
</div>
|
||||
<div class="body">
|
||||
<vn-descriptor-content
|
||||
module="entry"
|
||||
description="$ctrl.entry.supplier.nickname">
|
||||
<slot-menu>
|
||||
<vn-item
|
||||
ng-click="$ctrl.showEntryReport()"
|
||||
translate>
|
||||
Show entry report
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
<slot-body>
|
||||
<div class="attributes">
|
||||
<vn-label-value label="Id"
|
||||
value="{{$ctrl.entry.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Supplier"
|
||||
value="{{$ctrl.entry.supplier.nickname}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Agency "
|
||||
value="{{$ctrl.entry.travel.agency.name}}">
|
||||
</vn-label-value>
|
||||
|
@ -47,8 +35,23 @@
|
|||
ng-class="{bright: $ctrl.entry.isRaid}">
|
||||
</vn-icon>
|
||||
</div>
|
||||
<vn-quick-links
|
||||
links="$ctrl.quicklinks">
|
||||
</vn-quick-links>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quicklinks">
|
||||
<div ng-transclude="btnOne">
|
||||
<vn-quick-link
|
||||
tooltip="All travels with current agency"
|
||||
state="['travel.index', {q: $ctrl.travelFilter}]"
|
||||
icon="local_airport">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnTwo">
|
||||
<vn-quick-link
|
||||
tooltip="All entries with current supplier"
|
||||
state="['entry.index', {q: $ctrl.entryFilter}]"
|
||||
icon="icon-entry">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnThree">
|
||||
</div>
|
||||
</div>
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
|
|
|
@ -1,84 +1,52 @@
|
|||
import ngModule from '../module';
|
||||
import Component from 'core/lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $, $httpParamSerializer) {
|
||||
super($element, $);
|
||||
this.$httpParamSerializer = $httpParamSerializer;
|
||||
|
||||
this.moreOptions = [
|
||||
{name: 'Show entry report', callback: this.showEntryReport}
|
||||
];
|
||||
}
|
||||
|
||||
onMoreChange(callback) {
|
||||
callback.call(this);
|
||||
}
|
||||
import Descriptor from 'salix/components/descriptor';
|
||||
|
||||
class Controller extends Descriptor {
|
||||
get entry() {
|
||||
return this._entry;
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
set entry(value) {
|
||||
this._entry = value;
|
||||
if (!value) return;
|
||||
this.entity = value;
|
||||
}
|
||||
|
||||
const date = value.travel.landed;
|
||||
let to = new Date(date);
|
||||
let from = new Date(date);
|
||||
get travelFilter() {
|
||||
return this.entry && JSON.stringify({
|
||||
agencyFk: this.entry.travel.agencyFk
|
||||
});
|
||||
}
|
||||
|
||||
get entryFilter() {
|
||||
if (!this.entry) return null;
|
||||
|
||||
const date = new Date(this.entry.travel.landed);
|
||||
date.setHours(0, 0, 0, 0);
|
||||
|
||||
const from = new Date(date.getTime());
|
||||
from.setDate(from.getDate() - 10);
|
||||
|
||||
const to = new Date(date.getTime());
|
||||
to.setDate(to.getDate() + 10);
|
||||
|
||||
to.setHours(0, 0, 0, 0);
|
||||
|
||||
from.setDate(from.getDate() - 10);
|
||||
from.setHours(0, 0, 0, 0);
|
||||
|
||||
let links = {
|
||||
btnOne: {
|
||||
icon: 'local_airport',
|
||||
state: `travel.index({q: '{"agencyFk": ${value.travel.agencyFk}}'})`,
|
||||
tooltip: 'All travels with current agency'
|
||||
}};
|
||||
|
||||
links.btnTwo = {
|
||||
icon: 'icon-entry',
|
||||
state: `entry.index({q: '{"supplierFk": ${value.supplierFk}, "to": "${to}", "from": "${from}"}'})`,
|
||||
tooltip: 'All entries with current supplier'
|
||||
};
|
||||
|
||||
this._quicklinks = links;
|
||||
}
|
||||
|
||||
get quicklinks() {
|
||||
return this._quicklinks;
|
||||
}
|
||||
|
||||
set quicklinks(value = {}) {
|
||||
this._quicklinks = Object.assign(value, this._quicklinks);
|
||||
return JSON.stringify({
|
||||
supplierFk: this.entry.supplierFk,
|
||||
from,
|
||||
to
|
||||
});
|
||||
}
|
||||
|
||||
showEntryReport() {
|
||||
const params = {
|
||||
authorization: this.vnToken.token,
|
||||
this.showReport('entry-order', {
|
||||
clientId: this.vnConfig.storage.currentUserWorkerId,
|
||||
entryId: this.entry.id
|
||||
};
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
let url = `api/report/entry-order?${serializedParams}`;
|
||||
window.open(url);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];
|
||||
|
||||
ngModule.component('vnEntryDescriptor', {
|
||||
ngModule.vnComponent('vnEntryDescriptor', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
entry: '<',
|
||||
quicklinks: '<'
|
||||
},
|
||||
require: {
|
||||
card: '^?vnEntryCard'
|
||||
},
|
||||
controller: Controller
|
||||
entry: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,35 +1,26 @@
|
|||
import './index.js';
|
||||
|
||||
describe('Entry Component vnEntryDescriptor', () => {
|
||||
let $httpParamSerializer;
|
||||
let controller;
|
||||
let $element;
|
||||
const entry = {id: 2};
|
||||
|
||||
beforeEach(ngModule('entry'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, _$httpParamSerializer_) => {
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$element = angular.element(`<vn-entry-descriptor></vn-entry-descriptor>`);
|
||||
controller = $componentController('vnEntryDescriptor', {$element});
|
||||
controller._entry = {id: 2};
|
||||
controller.vnConfig.storage = {currentUserWorkerId: 9};
|
||||
controller.cardReload = ()=> {
|
||||
return true;
|
||||
};
|
||||
beforeEach(inject($componentController => {
|
||||
controller = $componentController('vnEntryDescriptor', {$element: null}, {entry});
|
||||
}));
|
||||
|
||||
describe('showEntryReport()', () => {
|
||||
it('should open a new window showing a delivery note PDF document', () => {
|
||||
controller.showReport = jest.fn();
|
||||
|
||||
const params = {
|
||||
clientId: controller.vnConfig.storage.currentUserWorkerId,
|
||||
entryId: controller.entry.id
|
||||
entryId: entry.id
|
||||
};
|
||||
const serializedParams = $httpParamSerializer(params);
|
||||
let expectedPath = `api/report/entry-order?${serializedParams}`;
|
||||
jest.spyOn(window, 'open').mockReturnThis();
|
||||
controller.showEntryReport();
|
||||
|
||||
expect(window.open).toHaveBeenCalledWith(expectedPath);
|
||||
expect(controller.showReport).toHaveBeenCalledWith('entry-order', params);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue