2612-create-supplier #1089

Merged
joan merged 21 commits from 2612-create-supplier into dev 2022-10-25 10:42:10 +00:00
15 changed files with 169 additions and 14 deletions

View File

@ -0,0 +1,2 @@
INSERT INTO `vn`.`payDem` (id,payDem)
pau marked this conversation as resolved Outdated
Outdated
Review

Nombre de esquema y tabla entre template strings ``

Nombre de esquema y tabla entre template strings ``
VALUES (7,'0');

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,principalId)
pau marked this conversation as resolved Outdated
Outdated
Review

Poner el nombre del esquema y la tabla entre template string (``), de lo contrario fallará al importar los cambios en producción.

Poner el nombre del esquema y la tabla entre template string (``), de lo contrario fallará al importar los cambios en producción.
VALUES ('Supplier','newSupplier','WRITE','administrative');

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`supplier` MODIFY COLUMN payMethodFk tinyint(3) unsigned NULL;
pau marked this conversation as resolved Outdated
Outdated
Review

Nombre de esquema y tabla entre template strings ``

Nombre de esquema y tabla entre template strings ``

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`supplier` MODIFY COLUMN supplierActivityFk varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL NULL;
pau marked this conversation as resolved Outdated
Outdated
Review

Nombre de esquema y tabla entre template strings ``

Nombre de esquema y tabla entre template strings ``

View File

@ -95,8 +95,8 @@ module.exports = Self => {
pm.name AS payMethod, pm.name AS payMethod,
pd.payDem AS payDem pd.payDem AS payDem
FROM vn.supplier s FROM vn.supplier s
JOIN vn.payMethod pm ON pm.id = s.payMethodFk LEFT JOIN vn.payMethod pm ON pm.id = s.payMethodFk
JOIN vn.payDem pd ON pd.id = s.payDemFk` LEFT JOIN vn.payDem pd ON pd.id = s.payDemFk`
); );
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));

View File

@ -0,0 +1,45 @@
module.exports = Self => {
Self.remoteMethod('newSupplier', {
description: 'Creates a new supplier and returns it',
pau marked this conversation as resolved Outdated
Outdated
Review

Corregir descripción

Corregir descripción
accessType: 'WRITE',
accepts: [{
arg: 'params',
type: 'object',
http: {source: 'body'}
}],
returns: {
type: 'string',
root: true
},
http: {
path: `/newSupplier`,
verb: 'POST'
}
});
Self.newSupplier = async params => {
const models = Self.app.models;
const myOptions = {};
if (typeof(params) == 'string')
pau marked this conversation as resolved Outdated
Outdated
Review

Esta propiedad no especificarla

Esta propiedad no especificarla
params = JSON.parse(params);
pau marked this conversation as resolved Outdated
Outdated
Review

Únicamente debería asignar la transacción si se la pasan a la función newSupplier(). No debe crear una transacción para una sola consulta.

Únicamente debería asignar la transacción si se la pasan a la función newSupplier(). No debe crear una transacción para una sola consulta.
params.nickname = params.name;
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const supplier = await models.Supplier.create(params, myOptions);
if (tx) await tx.commit();
return supplier;
} catch (e) {
if (tx) await tx.rollback();
return params;
}
};
};

View File

@ -10,7 +10,7 @@ describe('Supplier filter()', () => {
let result = await app.models.Supplier.filter(ctx); let result = await app.models.Supplier.filter(ctx);
expect(result.length).toEqual(1); expect(result.length).toBeGreaterThanOrEqual(1);
expect(result[0].id).toEqual(1); expect(result[0].id).toEqual(1);
}); });

View File

@ -0,0 +1,30 @@
const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('Supplier newSupplier()', () => {
const newSupp = {
name: 'TestSupplier-1'
};
const administrativeId = 5;
it('should create a new supplier containing only the name', async() => {
const activeCtx = {
accessToken: {userId: administrativeId},
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
expect(result.name).toEqual('TestSupplier-1');
expect(result.id).toEqual(443);
const createdSupplier = await app.models.Supplier.findById(result.id);
expect(createdSupplier.id).toEqual(result.id);
expect(createdSupplier.name).toEqual(result.name);
expect(createdSupplier.payDemFk).toEqual(7);
pau marked this conversation as resolved Outdated
Outdated
Review

Mantener únicamente los expects de los valores que esperas que estén rellenados (id, name, socialName)

Mantener únicamente los expects de los valores que esperas que estén rellenados (id, name, socialName)
expect(createdSupplier.nickname).toEqual(result.name);
});
});

View File

@ -10,6 +10,7 @@ module.exports = Self => {
require('../methods/supplier/freeAgencies')(Self); require('../methods/supplier/freeAgencies')(Self);
require('../methods/supplier/campaignMetricsPdf')(Self); require('../methods/supplier/campaignMetricsPdf')(Self);
require('../methods/supplier/campaignMetricsEmail')(Self); require('../methods/supplier/campaignMetricsEmail')(Self);
require('../methods/supplier/newSupplier')(Self);
Self.validatesPresenceOf('name', { Self.validatesPresenceOf('name', {
message: 'The social name cannot be empty' message: 'The social name cannot be empty'
@ -19,13 +20,17 @@ module.exports = Self => {
message: 'The supplier name must be unique' message: 'The supplier name must be unique'
}); });
Self.validatesPresenceOf('city', { if (this.city) {
message: 'City cannot be empty' Self.validatesPresenceOf('city', {
}); message: 'City cannot be empty'
});
}
Self.validatesPresenceOf('nif', { if (this.nif) {
message: 'The nif cannot be empty' Self.validatesPresenceOf('nif', {
}); message: 'The nif cannot be empty'
});
}
Self.validatesUniquenessOf('nif', { Self.validatesUniquenessOf('nif', {
message: 'TIN must be unique' message: 'TIN must be unique'
@ -57,6 +62,9 @@ module.exports = Self => {
} }
async function tinIsValid(err, done) { async function tinIsValid(err, done) {
if (!this.countryFk)
return done();
const filter = { const filter = {
fields: ['code'], fields: ['code'],
where: {id: this.countryFk} where: {id: this.countryFk}
@ -80,6 +88,7 @@ module.exports = Self => {
}); });
async function hasSupplierAccount(err, done) { async function hasSupplierAccount(err, done) {
if (!this.payMethodFk) return done();
const payMethod = await Self.app.models.PayMethod.findById(this.payMethodFk); const payMethod = await Self.app.models.PayMethod.findById(this.payMethodFk);
const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}}); const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}});
const hasIban = supplierAccount && supplierAccount.iban; const hasIban = supplierAccount && supplierAccount.iban;
@ -92,6 +101,7 @@ module.exports = Self => {
} }
Self.observe('before save', async function(ctx) { Self.observe('before save', async function(ctx) {
if (ctx.isNewInstance) return;
const loopbackContext = LoopBackContext.getCurrentContext(); const loopbackContext = LoopBackContext.getCurrentContext();
const changes = ctx.data || ctx.instance; const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance; const orgData = ctx.currentInstance;
@ -101,7 +111,7 @@ module.exports = Self => {
const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked; const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked;
const hasChanges = orgData && changes; const hasChanges = orgData && changes;
const isPayMethodCheckedChanged = hasChanges const isPayMethodCheckedChanged = hasChanges
&& orgData.isPayMethodChecked != isPayMethodChecked; && orgData.isPayMethodChecked != isPayMethodChecked;
if (isNotFinancial && isPayMethodCheckedChanged) if (isNotFinancial && isPayMethodCheckedChanged)
throw new UserError('You can not modify is pay method checked'); throw new UserError('You can not modify is pay method checked');
@ -114,7 +124,7 @@ module.exports = Self => {
const socialName = changes.name || orgData.name; const socialName = changes.name || orgData.name;
const hasChanges = orgData && changes; const hasChanges = orgData && changes;
const socialNameChanged = hasChanges const socialNameChanged = hasChanges
&& orgData.socialName != socialName; && orgData.socialName != socialName;
if ((socialNameChanged) && !isAlpha(socialName)) if ((socialNameChanged) && !isAlpha(socialName))
throw new UserError('The social name has an invalid format'); throw new UserError('The social name has an invalid format');

View File

@ -0,0 +1,29 @@
<vn-watcher
vn-id="watcher"
url="suppliers/newSupplier"
data="$ctrl.supplier"
insert-mode="true"
form="form">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
pau marked this conversation as resolved
Review

Este crud model parece que no se utiliza

Este crud model parece que no se utiliza
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield
label="Supplier name"
ng-model="$ctrl.supplier.name"
vn-focus>
</vn-textfield>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Create">
</vn-submit>
<vn-button
class="cancel"
label="Cancel"
ui-sref="supplier.index">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,23 @@
import ngModule from '../module';
import Section from 'salix/components/section';
class Controller extends Section {
constructor($element, $) {
super($element, $);
}
onSubmit() {
this.$.watcher.submit().then(
json => {
this.$state.go(`supplier.card.fiscalData`, {id: json.data.id});
pau marked this conversation as resolved Outdated
Outdated
Review

Supplier fiscaldata

Supplier fiscaldata
}
);
}
}
pau marked this conversation as resolved Outdated
Outdated
Review

Se debería utilizar únicamente el $state.go(), la función de abajo no es necesaria.

Se debería utilizar únicamente el $state.go(), la función de abajo no es necesaria.
Controller.$inject = ['$element', '$scope'];
ngModule.vnComponent('vnSupplierCreate', {
template: require('./index.html'),
controller: Controller
});

View File

@ -20,3 +20,4 @@ import './address/create';
import './address/edit'; import './address/edit';
import './agency-term/index'; import './agency-term/index';
import './agency-term/create'; import './agency-term/create';
import './create/index';

View File

@ -59,3 +59,6 @@
supplier="$ctrl.supplierSelected"> supplier="$ctrl.supplierSelected">
</vn-supplier-summary> </vn-supplier-summary>
</vn-popup> </vn-popup>
<a vn-acl-action="remove" vn-acl="administrative" ui-sref="supplier.create" vn-tooltip="New supplier" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -3,3 +3,4 @@ Pay day: Dia de pago
Account: Cuenta Account: Cuenta
Pay method: Metodo de pago Pay method: Metodo de pago
Tax number: Nif Tax number: Nif
New supplier: Nuevo proveedor

View File

@ -52,6 +52,13 @@
"supplier": "$ctrl.supplier" "supplier": "$ctrl.supplier"
} }
}, },
{
"url": "/create",
"state": "supplier.create",
"component": "vn-supplier-create",
"acl": ["administrative"],
pau marked this conversation as resolved Outdated
Outdated
Review

Falta especificar el ACL administrative

Falta especificar el ACL administrative
"description": "New supplier"
},
{ {
"url": "/basic-data", "url": "/basic-data",
"state": "supplier.card.basicData", "state": "supplier.card.basicData",