Merge branch 'dev' of http://git.verdnatura.es/salix into dev

This commit is contained in:
Carlos Jimenez 2018-10-18 11:42:56 +02:00
commit 7093660800
16 changed files with 278 additions and 107 deletions

View File

@ -40,7 +40,7 @@
<vn-td number>{{::zone.price | currency:'€':2}}</vn-td> <vn-td number>{{::zone.price | currency:'€':2}}</vn-td>
<vn-td> <vn-td>
<vn-icon-button <vn-icon-button
ng-click="$ctrl.preview($event, zone)" ng-click="$ctrl.preview(zone)"
vn-tooltip="Preview" vn-tooltip="Preview"
icon="desktop_windows"> icon="desktop_windows">
</vn-icon-button> </vn-icon-button>

View File

@ -42,7 +42,7 @@
<vn-td>{{::claim.claimState.description}}</vn-td> <vn-td>{{::claim.claimState.description}}</vn-td>
<vn-td> <vn-td>
<vn-icon-button <vn-icon-button
ng-click="$ctrl.preview($event, claim)" ng-click="$ctrl.preview(claim)"
vn-tooltip="Preview" vn-tooltip="Preview"
icon="desktop_windows"> icon="desktop_windows">
</vn-icon-button> </vn-icon-button>

View File

@ -10,7 +10,7 @@
<vn-title>Pay method</vn-title> <vn-title>Pay method</vn-title>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-two vn-one
label="Pay method" label="Pay method"
vn-acl="salesAssistant" vn-acl="salesAssistant"
field="$ctrl.client.payMethodFk" field="$ctrl.client.payMethodFk"
@ -18,7 +18,21 @@
select-fields="ibanRequired" select-fields="ibanRequired"
initial-data="$ctrl.client.payMethod"> initial-data="$ctrl.client.payMethod">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-two <vn-textfield
vn-one
label="Due day"
field="$ctrl.client.dueDay"
vn-acl="salesAssistant">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="IBAN"
field="$ctrl.client.iban"
vn-acl="salesAssistant">
</vn-textfield>
<vn-autocomplete vn-one
label="Swift / BIC" label="Swift / BIC"
url="/client/api/BankEntities" url="/client/api/BankEntities"
field="$ctrl.client.bankEntityFk" field="$ctrl.client.bankEntityFk"
@ -37,20 +51,12 @@
</vn-horizontal> </vn-horizontal>
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield <vn-icon-button vn-auto margin-medium-v
vn-one icon="add_circle"
label="Due day" vn-tooltip="New bank entity"
field="$ctrl.client.dueDay" vn-dialog="bankEntityDialog"
vn-acl="salesAssistant"> vn-acl="salesAssistant">
</vn-textfield> </vn-icon-button>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="IBAN"
field="$ctrl.client.iban"
vn-acl="salesAssistant">
</vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal pad-small-v> <vn-horizontal pad-small-v>
<vn-one> <vn-one>
@ -79,4 +85,39 @@
<vn-button-bar> <vn-button-bar>
<vn-submit label="Save" vn-acl="salesAssistant"></vn-submit> <vn-submit label="Save" vn-acl="salesAssistant"></vn-submit>
</vn-button-bar> </vn-button-bar>
</form> </form>
<!-- Create bank entity dialog -->
<vn-dialog class="edit"
vn-id="bankEntityDialog"
on-open="$ctrl.onBankEntityOpen()"
on-response="$ctrl.onBankEntityResponse(response)">
<tpl-body>
<h5 pad-small-v translate>New bank entity</h5>
<vn-horizontal>
<vn-textfield vn-one
label="Name"
model="$ctrl.newBankEntity.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Country"
field="$ctrl.newBankEntity.countryFk"
url="/client/api/Countries"
value-field="id"
show-field="country">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one
label="Swift / BIC"
model="$ctrl.newBankEntity.bic">
</vn-textfield>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Create</button>
</tpl-buttons>
</vn-dialog>

View File

@ -5,7 +5,21 @@ export default class Controller {
this.$scope = $scope; this.$scope = $scope;
this.$http = $http; this.$http = $http;
this.vnApp = vnApp; this.vnApp = vnApp;
this.translate = $translate; this.$translate = $translate;
}
get client() {
return this._client;
}
set client(value) {
this._client = value;
if (!value) return;
this.newBankEntity = {
countryFk: Number.parseInt(value.countryFk)
};
} }
onSubmit() { onSubmit() {
@ -22,7 +36,7 @@ export default class Controller {
notifyChanges() { notifyChanges() {
this.$http.get(`/mailer/notification/payment-update/${this.client.id}`).then( this.$http.get(`/mailer/notification/payment-update/${this.client.id}`).then(
() => this.vnApp.showMessage(this.translate.instant('Notification sent!')) () => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
); );
} }
@ -35,6 +49,32 @@ export default class Controller {
return payMethod || iban || dueDay; return payMethod || iban || dueDay;
} }
onBankEntityOpen() {
this.newBankEntity.name = '';
this.newBankEntity.bic = '';
this.$scope.$apply();
}
onBankEntityResponse(response) {
if (response == 'ACCEPT')
try {
if (!this.newBankEntity.name)
throw new Error(`Name can't be empty`);
if (!this.newBankEntity.bic)
throw new Error(`Swift / BIC can't be empty`);
this.$http.post(`/client/api/BankEntities`, this.newBankEntity).then(response => {
if (response.data)
this.client.bankEntityFk = response.data.id;
});
} catch (e) {
this.vnApp.showError(this.$translate.instant(e.message));
return false;
}
return true;
}
} }
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate']; Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];

View File

@ -7,17 +7,20 @@ describe('Client', () => {
let $httpBackend; let $httpBackend;
let $scope; let $scope;
let controller; let controller;
let vnApp;
beforeEach(() => { beforeEach(() => {
angular.mock.module('client'); angular.mock.module('client');
}); });
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => { beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _vnApp_) => {
$componentController = _$componentController_; $componentController = _$componentController_;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({}); $httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$scope.watcher = watcher; $scope.watcher = watcher;
vnApp = _vnApp_;
spyOn(vnApp, 'showError');
controller = $componentController('vnClientBillingData', {$scope: $scope}); controller = $componentController('vnClientBillingData', {$scope: $scope});
controller.client = {id: 101, name: 'Client name', payMethodFk: 4}; controller.client = {id: 101, name: 'Client name', payMethodFk: 4};
$scope.watcher.orgData = {id: 101, name: 'Client name', payMethodFk: 4}; $scope.watcher.orgData = {id: 101, name: 'Client name', payMethodFk: 4};
@ -55,5 +58,53 @@ describe('Client', () => {
expect(controller.hasPaymethodChanges()).toBeFalsy(); expect(controller.hasPaymethodChanges()).toBeFalsy();
}); });
}); });
describe('onBankEntityOpen()', () => {
it('should set reset the new bank entity properties', () => {
controller.newBankEntity.name = 'My new bank entity';
controller.newBankEntity.bic = 'ES123';
controller.onBankEntityOpen();
expect(controller.newBankEntity.name).toBe('');
expect(controller.newBankEntity.bic).toBe('');
});
});
describe('onBankEntityResponse()', () => {
it(`should throw an error if name property is empty`, () => {
controller.newBankEntity = {
name: '',
bic: 'ES123',
countryFk: 1
};
controller.onBankEntityResponse('ACCEPT');
expect(vnApp.showError).toHaveBeenCalledWith(`Name can't be empty`);
});
it(`should throw an error if bic property is empty`, () => {
controller.newBankEntity = {
name: 'My new bank entity',
bic: '',
countryFk: 1
};
controller.onBankEntityResponse('ACCEPT');
expect(vnApp.showError).toHaveBeenCalledWith(`Swift / BIC can't be empty`);
});
it('should request to create a new bank entity', () => {
let newBankEntity = {
name: 'My new bank entity',
bic: 'ES123',
countryFk: 1
};
controller.newBankEntity = newBankEntity;
$httpBackend.when('POST', '/client/api/BankEntities').respond('done');
$httpBackend.expectPOST('/client/api/BankEntities', newBankEntity);
controller.onBankEntityResponse('ACCEPT');
$httpBackend.flush();
});
});
}); });
}); });

View File

@ -12,4 +12,7 @@ Due day: Vencimiento
Received LCR: Recibido LCR Received LCR: Recibido LCR
Received core VNL: Recibido core VNL Received core VNL: Recibido core VNL
Received B2B VNL: Recibido B2B VNL Received B2B VNL: Recibido B2B VNL
Save: Guardar Save: Guardar
New bank entity: Nueva entidad bancaria
Name can't be empty: El nombre no puede quedar vacío
Swift / BIC can't be empty: El Swift / BIC no puede quedar vacío

View File

@ -29,7 +29,7 @@
vn-acl-action="remove" vn-acl-action="remove"
vn-tooltip="Finish that recovery period" vn-tooltip="Finish that recovery period"
ng-if="!recovery.finished" ng-if="!recovery.finished"
on-click="$ctrl.setFinished(recovery)"> ng-click="$ctrl.setFinished(recovery)">
</vn-icon-button> </vn-icon-button>
</vn-td> </vn-td>
<vn-td>{{::recovery.started | date:'dd/MM/yyyy' }}</vn-td> <vn-td>{{::recovery.started | date:'dd/MM/yyyy' }}</vn-td>

View File

@ -1,10 +1,11 @@
import ngModule from '../module'; import ngModule from '../module';
export default class Controller { export default class Controller {
constructor($scope, $http, vnApp) { constructor($scope, $http, vnApp, $translate) {
this.$ = $scope; this.$ = $scope;
this.$http = $http; this.$http = $http;
this.vnApp = vnApp; this.vnApp = vnApp;
this.$translate = $translate;
this.canChangePassword = false; this.canChangePassword = false;
this.canEnableCheckBox = true; this.canEnableCheckBox = true;
} }
@ -52,14 +53,14 @@ export default class Controller {
this.$http.patch(`/client/api/Accounts/${this.client.id}`, account); this.$http.patch(`/client/api/Accounts/${this.client.id}`, account);
} catch (e) { } catch (e) {
this.vnApp.showError(e.message); this.vnApp.showError(this.$translate.instant(e.message));
return false; return false;
} }
return true; return true;
} }
} }
Controller.$inject = ['$scope', '$http', 'vnApp']; Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];
ngModule.component('vnClientWebAccess', { ngModule.component('vnClientWebAccess', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -29,7 +29,7 @@
vn-acl="administrative" vn-acl="administrative"
vn-tooltip="Confirm transaction" vn-tooltip="Confirm transaction"
ng-show="::!transaction.isConfirmed" ng-show="::!transaction.isConfirmed"
on-click="$ctrl.confirm(transaction)"> ng-click="$ctrl.confirm(transaction)">
</vn-icon-button> </vn-icon-button>
</vn-td> </vn-td>
<vn-td>{{::transaction.id}}</vn-td> <vn-td>{{::transaction.id}}</vn-td>

View File

@ -1,3 +1,3 @@
<button ng-click="$ctrl.onClick()"> <button type="button" ng-disabled="{{$ctrl.disabled}}">
<vn-icon icon="{{::$ctrl.icon}}"> <vn-icon icon="{{::$ctrl.icon}}">
</button> </button>

View File

@ -5,7 +5,13 @@ export default class IconButton {
constructor($element) { constructor($element) {
if ($element[0].getAttribute('tabindex') == null) if ($element[0].getAttribute('tabindex') == null)
$element[0].tabIndex = 0; $element[0].tabIndex = 0;
$element.on("keyup", event => this.onKeyDown(event, $element)); $element.on("keyup", event => this.onKeyDown(event, $element));
let button = $element[0].querySelector('button');
$element[0].addEventListener('click', event => {
if (this.disabled || button.disabled)
event.stopImmediatePropagation();
});
} }
onKeyDown(event, $element) { onKeyDown(event, $element) {
@ -23,8 +29,6 @@ ngModule.component('vnIconButton', {
template: require('./icon-button.html'), template: require('./icon-button.html'),
bindings: { bindings: {
icon: '@', icon: '@',
onClick: '&?', disabled: '<?'
enabled: '<?'
} }
}); });

View File

@ -1,8 +1 @@
<div id="shapes"></div> <div id="shapes"></div>
<!-- <div ng-click="$ctrl.onSnackbarClick($event)">
<button ng-click="$ctrl.onButtonClick()"></button>
<div class="text"></div>
</div>
-->

View File

@ -56,16 +56,14 @@
show-field="name" show-field="name"
value-field="name"> value-field="name">
</vn-autocomplete> </vn-autocomplete>
<vn-none> <vn-icon-button vn-none
<vn-icon-button medium-grey
medium-grey margin-medium-v
margin-medium-v vn-tooltip="Remove tag"
vn-tooltip="Remove tag" icon="remove_circle_outline"
icon="remove_circle_outline" ng-click="filter.tags.splice($index, 1)"
ng-click="filter.tags.splice($index, 1)" tabindex="-1">
tabindex="-1"> </vn-icon-button>
</vn-icon-button>
</vn-none>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-icon-button <vn-icon-button

View File

@ -48,9 +48,7 @@ export default class Controller {
this.$scope.popover.relocate(); this.$scope.popover.relocate();
} }
preview(event, order) { preview(order) {
event.preventDefault();
event.stopImmediatePropagation();
this.$scope.orderSummaryDialog.show(); this.$scope.orderSummaryDialog.show();
this.order = order; this.order = order;
} }

View File

@ -6,4 +6,8 @@ CHANGE COLUMN `newInstance` `newInstance` TEXT NULL DEFAULT NULL ;
ALTER TABLE `vn`.`clientLog` ALTER TABLE `vn`.`clientLog`
CHANGE COLUMN `model` `changedModel` TEXT CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL , CHANGE COLUMN `model` `changedModel` TEXT CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
ADD COLUMN `changedModelId` INT(11) NULL DEFAULT NULL AFTER `newInstance`, ADD COLUMN `changedModelId` INT(11) NULL DEFAULT NULL AFTER `newInstance`,
ADD COLUMN `changedModelValue` INT(11) NULL DEFAULT NULL AFTER `changedModelId`; ADD COLUMN `changedModelValue` VARCHAR(45) NULL DEFAULT NULL AFTER `changedModelId`;
ALTER TABLE `vn`.`clientLog`
CHANGE COLUMN `changedModel` `changedModel` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ;

View File

@ -6,7 +6,7 @@ module.exports = function(Self) {
Self.super_.setup.call(this); Self.super_.setup.call(this);
}; };
Self.observe('after save', async function(ctx) { /* Self.observe('after save', async function(ctx) {
const loopBackContext = LoopBackContext.getCurrentContext(); const loopBackContext = LoopBackContext.getCurrentContext();
await logInModel(ctx, loopBackContext); await logInModel(ctx, loopBackContext);
}); });
@ -27,49 +27,58 @@ module.exports = function(Self) {
ctx.hookState.newInstance = newInstance; ctx.hookState.newInstance = newInstance;
}); });
/* Self.observe('before delete', async function(ctx, next) { Self.observe('before delete', async function(ctx) {
let oldInstance; let oldInstance;
if (ctx.instance) { // console.log(ctx.where);
oldInstance = await fkToValue(ctx.data, ctx); if (ctx.where) {
} let affectedModel = ctx.Model.definition.name;
await logInModel(ctx); // console.log(affectedModel);
let deletedInstances = await Self.modelBuilder.models[affectedModel].find({where: ctx.where});
// console.log(deletedInstances);
next(); let arrangedDeletedInstances = [];
deletedInstances.forEach(async element => {
console.log(element);
arrangedDeletedInstances.push(await fkToValue(element, ctx));
});
console.log(arrangedDeletedInstances);
// let deletedIntancesData = await fkToValue(deletedInstances, ctx);
// console.log(deletedIntancesData);
// oldInstanceFk = pick(ctx.currentInstance, Object.keys(ctx.data));
// oldInstance = await fkToValue(oldInstanceFk, ctx);
}
ctx.hookState.oldInstance = oldInstance;
}); });
Self.observe('after delete', async function(ctx, next) { Self.observe('after delete', async function(ctx) {
let oldInstance; const loopBackContext = LoopBackContext.getCurrentContext();
if (ctx.instance) { await logInModel(ctx, loopBackContext);
oldInstance = await fkToValue(ctx.data, ctx); }); */
}
await logInModel(ctx);
next();
});
*/
async function fkToValue(instance, ctx) { async function fkToValue(instance, ctx) {
let result = {}; let result = {};
for (let key in instance) { for (let key in instance) {
if (key == 'id') continue; if (key == 'id') continue;
let val = instance[key]; let val = instance[key];
if (val === undefined) continue; console.log(val);
if (val === undefined || val === null) continue;
for (let key1 in ctx.Model.relations) { for (let key1 in ctx.Model.relations) {
let val1 = ctx.Model.relations[key1]; let val1 = ctx.Model.relations[key1];
if (val1.keyFrom == key) { if (val1.keyFrom == key) {
let recordSet = await val1.modelTo.findById(val); let recordSet = await val1.modelTo.findById(val);
val = recordSet.name; // FIXME preparar todos los modelos con campo name val = recordSet.name; // FIXME preparar todos los modelos con campo name
console.log(val);
break; break;
} }
} }
result[key] = val; result[key] = val;
} }
// console.log(result);
return result; return result;
} }
async function logInModel(ctx, loopBackContext) { async function logInModel(ctx, loopBackContext) {
let definition = ctx.Model.definition; let definition = ctx.Model.definition;
let primaryKey; let primaryKey;
for (let property in definition.properties) { for (let property in definition.properties) {
@ -78,83 +87,112 @@ module.exports = function(Self) {
break; break;
} }
} }
if (!primaryKey) throw new Error('Primary key not found'); if (!primaryKey) throw new Error('Primary key not found');
let originId; let originId;
if (definition.settings.log.relation) { // RELATIONS LOG
// RELATIONS LOG let changedModelId;
if (ctx.instance && !definition.settings.log.relation) {
originId = ctx.instance.id;
changedModelId = ctx.instance.id;
} else if (definition.settings.log.relation) {
primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom; primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom;
if(ctx.where && ctx.where[primaryKey]) if (ctx.where && ctx.where[primaryKey])
originId = ctx.where[primaryKey] originId = ctx.where[primaryKey];
else else {
originId = ctx.instance[primaryKey]; originId = ctx.instance[primaryKey];
} else { changedModelId = ctx.instance.id;
if (ctx.instance) {
originId = ctx.instance.id;
} else {
originId = ctx.currentInstance.id;
} }
} else {
originId = ctx.currentInstance.id;
changedModelId = ctx.currentInstance.id;
} }
// This adds the originDescription field if it doesnt exists in the instances // console.log(ctx.instance, ctx.where, ctx.currentInstance);
let originDescription = definition.settings.log.originDescription; // Sets the changedModelValue to save and the instances changed in case its an updateAll
let changedModelValue = definition.settings.log.changedModelValue;
if (originDescription && (!ctx.instance || !ctx.instance[originDescription])) if (changedModelValue && (!ctx.instance || !ctx.instance[changedModelValue])) {
await Self.modelBuilder.models[definition.name].findById() var where = [];
changedModelId = [];
if (ctx.hookState.oldInstance && !ctx.hookState.oldInstance[originDescription]){ let changedInstances = await Self.modelBuilder.models[definition.name].find({where: ctx.where, fields: ['id', changedModelValue]});
ctx.hookState.oldInstance[originDescription] = ctx.instance[originDescription]; changedInstances.forEach(element => {
ctx.hookState.newInstance[originDescription] = ctx.instance[originDescription]; where.push(element[changedModelValue]);
changedModelId.push(element.id);
});
} else if (ctx.hookState.oldInstance) {
where = ctx.instance[changedModelValue];
} }
// console.log(where);
// This put some order in the intances putting the originDescription in first place // Set oldInstance, newInstance, userFk and action
let oldInstance = {}; let oldInstance = {};
if (ctx.hookState.oldInstance) { if (ctx.hookState.oldInstance) {
oldInstance[originDescription] = ctx.hookState.oldInstance[originDescription];
delete ctx.hookState.oldInstance[originDescription];
Object.assign(oldInstance, ctx.hookState.oldInstance); Object.assign(oldInstance, ctx.hookState.oldInstance);
} }
let newInstance = {}; let newInstance = {};
if (ctx.hookState.newInstance) { if (ctx.hookState.newInstance) {
newInstance[originDescription] = ctx.hookState.newInstance[originDescription]; Object.assign(newInstance, ctx.hookState.newInstance);
delete ctx.hookState.newInstance[originDescription];
Object.assign(newInstance, ctx.hookState.newInstance)
} }
let userFk; let userFk;
if (!loopBackContext) userFk = null; if (loopBackContext)
else userFk = loopBackContext.active.accessToken.userId; userFk = loopBackContext.active.accessToken.userId;
let action = setActionType(ctx); let action = setActionType(ctx);
let logRecord = { let logRecord = {
originFk: originId, originFk: originId,
userFk: userFk, userFk: userFk,
model: ctx.Model.definition.name,
action: action, action: action,
changedModel: ctx.Model.definition.name,
changedModelId: changedModelId,
changedModelValue: where,
oldInstance: oldInstance, oldInstance: oldInstance,
newInstance: newInstance newInstance: newInstance
}; };
let logsToSave = setLogsToSave(where, changedModelId, logRecord);
let logModel = definition.settings.log.model let logModel = definition.settings.log.model;
await Self.modelBuilder.models[logModel].create(logRecord);
let transaction = {};
if (ctx.options && ctx.options.transaction) {
transaction = ctx.options.transaction;
}
// console.log(logsToSave);
await Self.modelBuilder.models[logModel].create(logsToSave, transaction);
}
// this function retuns all the instances changed in case this is an updateAll
function setLogsToSave(changedInstances, changedInstancesIds, logRecord) {
let promises = [];
if (changedInstances && typeof changedInstances == "object") {
for (let i = 0; i < changedInstances.length; i++) {
logRecord.changedModelId = changedInstancesIds[i];
logRecord.changedModelValue = changedInstances[i];
promises.push(JSON.parse(JSON.stringify(logRecord)));
}
} else {
return logRecord;
}
return promises;
} }
function setActionType(ctx) { function setActionType(ctx) {
let oldInstance = ctx.hookState.oldInstance; let oldInstance = ctx.hookState.oldInstance;
let newInstance = ctx.hookState.newInstance; let newInstance = ctx.hookState.newInstance;
if (oldInstance && newInstance) { if (oldInstance && newInstance) {
return 'update'; return 'update';
} else if (!oldInstance && newInstance) { } else if (!oldInstance && newInstance) {
return 'insert'; return 'insert';
} }
return 'delete';
} }
}; };