Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2020-11-07 01:19:32 +01:00
commit b3b70b1585
27 changed files with 1906 additions and 1225 deletions

View File

@ -1,6 +1,6 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
const testAuth = (z , bundle) => { const test = (z , bundle) => {
const url = bundle.authData.url+'/api/index.php/login'; const url = bundle.authData.url+'/api/index.php/status';
// Normally you want to make a request to an endpoint that is either specifically designed to test auth, or one that // Normally you want to make a request to an endpoint that is either specifically designed to test auth, or one that
// every user will have access to, such as an account or profile endpoint like /me. // every user will have access to, such as an account or profile endpoint like /me.
// In this example, we'll hit httpbin, which validates the Authorization Header against the arguments passed in the URL path // In this example, we'll hit httpbin, which validates the Authorization Header against the arguments passed in the URL path
@ -11,44 +11,69 @@ const testAuth = (z , bundle) => {
// This method can return any truthy value to indicate the credentials are valid. // This method can return any truthy value to indicate the credentials are valid.
// Raise an error to show // Raise an error to show
return promise.then((response) => { return promise.then((response) => {
if (response.status === 401) { if (response.status === 400) {
throw new Error('The Session Key you supplied is invalid'); throw new Error('400 -The Session Key you supplied is invalid');
}
if (response.status === 403) {
throw new Error('403 -The Session Key you supplied is invalid');
} }
return response; return response;
}); });
}; };
const getSessionKey = (z, bundle) => { // To include the session key header on all outbound requests, simply define a function here.
// It runs runs before each request is sent out, allowing you to make tweaks to the request in a centralized spot
const includeSessionKeyHeader = (request, z, bundle) => {
if (bundle.authData.sessionKey) {
request.headers = request.headers || {};
request.headers['DOLAPIKEY'] = bundle.authData.sessionKey;
}
return request;
};
// If we get a response and it is a 401, we can raise a special error telling Zapier to retry this after another exchange.
const sessionRefreshIf401 = (response, z, bundle) => {
if (bundle.authData.sessionKey) {
if (response.status === 401) {
throw new z.errors.RefreshAuthError('Session apikey needs refreshing.');
}
}
return response;
};
const getSessionKey = async (z, bundle) => {
const url = bundle.authData.url + '/api/index.php/login'; const url = bundle.authData.url + '/api/index.php/login';
const promise = z.request({ const response = await z.request({
method: 'POST',
url: url, url: url,
method: 'POST',
body: { body: {
login: bundle.authData.login, login: bundle.authData.login,
password: bundle.authData.password, password: bundle.authData.password,
} },
}); });
return promise.then((response) => { // if (response.status === 401) {
if (response.status === 401) { // throw new Error('The login/password you supplied is invalid');
throw new Error('The login/password you supplied is invalid'); // }
}
const json = JSON.parse(response.content); const json = JSON.parse(response.content);
return { return {
sessionKey: json.success.token || 'secret' sessionKey: json.success.token || '',
}; };
});
}; };
module.exports = { module.exports = {
config: {
type: 'session', type: 'session',
sessionConfig: {
perform: getSessionKey
},
// Define any auth fields your app requires here. The user will be prompted to enter this info when // Define any auth fields your app requires here. The user will be prompted to enter this info when
// they connect their account. // they connect their account.
fields: [ fields: [
{ {
key: 'url', key: 'url',
label: 'Url of service', label: 'Url of service without trailing-slash',
required: true, required: true,
type: 'string' type: 'string'
}, },
@ -67,11 +92,11 @@ module.exports = {
], ],
// The test method allows Zapier to verify that the credentials a user provides are valid. We'll execute this // The test method allows Zapier to verify that the credentials a user provides are valid. We'll execute this
// method whenever a user connects their account for the first time. // method whenever a user connects their account for the first time.
test: testAuth, test,
// The method that will exchange the fields provided by the user for session credentials. // The method that will exchange the fields provided by the user for session credentials.
sessionConfig: {
perform: getSessionKey
},
// assuming "login" is a key returned from the test // assuming "login" is a key returned from the test
connectionLabel: '{{login}}' connectionLabel: '{{login}}'
},
befores: [includeSessionKeyHeader],
afters: [sessionRefreshIf401],
}; };

View File

@ -72,7 +72,7 @@ module.exports = {
}, },
outputFields: [ outputFields: [
{key: 'id', label: 'ID'}, {key: 'id', type: "integer", label: 'ID'},
{key: 'name', label: 'Name'}, {key: 'name', label: 'Name'},
{key: 'name_alias', label: 'Name alias'}, {key: 'name_alias', label: 'Name alias'},
{key: 'address', label: 'Address'}, {key: 'address', label: 'Address'},
@ -81,8 +81,8 @@ module.exports = {
{key: 'phone', label: 'Phone'}, {key: 'phone', label: 'Phone'},
{key: 'fax', label: 'Fax'}, {key: 'fax', label: 'Fax'},
{key: 'email', label: 'Email'}, {key: 'email', label: 'Email'},
{key: 'client', label: 'Customer/Prospect 0/1/2/3'}, {key: 'client', type: "integer", label: 'Customer/Prospect 0/1/2/3'},
{key: 'fournisseur', label: 'Supplier 0/1'}, {key: 'fournisseur', type: "integer", label: 'Supplier 0/1'},
{key: 'code_client', label: 'Customer code'}, {key: 'code_client', label: 'Customer code'},
{key: 'code_fournisseur', label: 'Supplier code'} {key: 'code_fournisseur', label: 'Supplier code'}
] ]

View File

@ -1,33 +1,39 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
const triggerThirdparty = require('./triggers/thirdparty');
const triggerOrder = require('./triggers/order');
const triggerAction = require('./triggers/action'); const triggerAction = require('./triggers/action');
const triggerOrder = require('./triggers/order');
const triggerThirdparty = require('./triggers/thirdparty');
const triggerTicket = require('./triggers/ticket');
const triggerUser = require('./triggers/user');
const searchThirdparty = require('./searches/thirdparty'); const searchThirdparty = require('./searches/thirdparty');
const createThirdparty = require('./creates/thirdparty'); const createThirdparty = require('./creates/thirdparty');
const authentication = require('./authentication'); const {
config: authentication,
befores = [],
afters = [],
} = require('./authentication');
// To include the session key header on all outbound requests, simply define a function here. // To include the session key header on all outbound requests, simply define a function here.
// It runs runs before each request is sent out, allowing you to make tweaks to the request in a centralized spot // It runs runs before each request is sent out, allowing you to make tweaks to the request in a centralized spot
const includeSessionKeyHeader = (request, z, bundle) => { // const includeSessionKeyHeader = (request, z, bundle) => {
if (bundle.authData.sessionKey) { // if (bundle.authData.sessionKey) {
request.headers = request.headers || {}; // request.headers = request.headers || {};
request.headers['DOLAPIKEY'] = bundle.authData.sessionKey; // request.headers['DOLAPIKEY'] = bundle.authData.sessionKey;
} // }
return request; // return request;
}; // };
// If we get a response and it is a 401, we can raise a special error telling Zapier to retry this after another exchange. // If we get a response and it is a 401, we can raise a special error telling Zapier to retry this after another exchange.
const sessionRefreshIf401 = (response, z, bundle) => { // const sessionRefreshIf401 = (response, z, bundle) => {
if (bundle.authData.sessionKey) { // if (bundle.authData.sessionKey) {
if (response.status === 401) { // if (response.status === 401) {
throw new z.errors.RefreshAuthError('Session apikey needs refreshing.'); // throw new z.errors.RefreshAuthError('Session apikey needs refreshing.');
} // }
} // }
return response; // return response;
}; // };
// We can roll up all our behaviors in an App. // We can roll up all our behaviors in an App.
const App = { const App = {
@ -40,11 +46,11 @@ const App = {
// beforeRequest & afterResponse are optional hooks into the provided HTTP client // beforeRequest & afterResponse are optional hooks into the provided HTTP client
beforeRequest: [ beforeRequest: [
includeSessionKeyHeader ...befores
], ],
afterResponse: [ afterResponse: [
sessionRefreshIf401 ...afters
], ],
// If you want to define optional resources to simplify creation of triggers, searches, creates - do that here! // If you want to define optional resources to simplify creation of triggers, searches, creates - do that here!
@ -53,9 +59,11 @@ const App = {
// If you want your trigger to show up, you better include it here! // If you want your trigger to show up, you better include it here!
triggers: { triggers: {
[triggerThirdparty.key]: triggerThirdparty, [triggerAction.key]: triggerAction,
[triggerOrder.key]: triggerOrder, [triggerOrder.key]: triggerOrder,
[triggerAction.key]: triggerAction [triggerThirdparty.key]: triggerThirdparty,
[triggerTicket.key]: triggerTicket,
[triggerUser.key]: triggerUser,
}, },
// If you want your searches to show up, you better include it here! // If you want your searches to show up, you better include it here!

View File

@ -1,6 +1,6 @@
{ {
"name": "dolibarr", "name": "dolibarr",
"version": "1.0.0", "version": "1.13.0",
"description": "An app for connecting Dolibarr to the Zapier platform.", "description": "An app for connecting Dolibarr to the Zapier platform.",
"repository": "Dolibarr/dolibarr", "repository": "Dolibarr/dolibarr",
"homepage": "https://www.dolibarr.org/", "homepage": "https://www.dolibarr.org/",
@ -15,7 +15,7 @@
"npm": ">=5.6.0" "npm": ">=5.6.0"
}, },
"dependencies": { "dependencies": {
"zapier-platform-core": "8.0.1" "zapier-platform-core": "10.1.1"
}, },
"devDependencies": { "devDependencies": {
"mocha": "^5.2.0", "mocha": "^5.2.0",

View File

@ -54,13 +54,20 @@ module.exports = {
// outputFields: () => { return []; } // outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields // Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [ outputFields: [
{key: 'id', label: 'ID'}, {
{key: 'createdAt', label: 'Created At'}, key: 'id',
type: "integer",
label: 'ID'
},
{key: 'createdAt', type: "integer", label: 'Created At'},
{key: 'name', label: 'Name'}, {key: 'name', label: 'Name'},
{key: 'firstname', label: 'Firstname'}, {key: 'firstname', label: 'Firstname'},
{key: 'directions', label: 'Directions'}, {key: 'directions', label: 'Directions'},
{key: 'authorId', label: 'Author ID'}, {key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'style', label: 'Style'} {
key: 'style',
label: 'Style'
}
] ]
} }
}; };

View File

@ -17,7 +17,7 @@ const subscribeHook = (z, bundle) => {
const options = { const options = {
url: url, url: url,
method: 'POST', method: 'POST',
body: JSON.stringify(data) body: data,
}; };
// You may return a promise or a normal data structure from any perform method. // You may return a promise or a normal data structure from any perform method.
@ -100,7 +100,7 @@ module.exports = {
noun: 'Action', noun: 'Action',
display: { display: {
label: 'New Agenda', label: 'New Agenda',
description: 'Trigger when a new agenda with action is done in Dolibarr.' description: 'Triggers when a new agenda with action is done in Dolibarr.'
}, },
// `operation` is where the business logic goes. // `operation` is where the business logic goes.
@ -111,6 +111,7 @@ module.exports = {
inputFields: [ inputFields: [
{ {
key: 'action', key: 'action',
required: true,
type: 'string', type: 'string',
helpText: 'Which action of agenda this should trigger on.', helpText: 'Which action of agenda this should trigger on.',
choices: { choices: {
@ -145,12 +146,33 @@ module.exports = {
// outputFields: () => { return []; } // outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields // Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [ outputFields: [
{key: 'id', label: 'ID'}, {
{key: 'createdAt', label: 'Created At'}, key: 'id',
{key: 'name', label: 'Name'}, type: "integer",
{key: 'usertodo__name', label: 'UserToDo Name'}, label: 'ID'
{key: 'authorId', label: 'Author ID'}, },
{key: 'action', label: 'Action'} {
key: 'createdAt',
type: "integer",
label: 'Created At'
},
{
key: 'name',
label: 'Name'
},
{
key: 'usertodo__name',
label: 'UserToDo Name'
},
{
key: 'authorId',
type: "integer",
label: 'Author ID'
},
{
key: 'action',
label: 'Action'
}
] ]
} }
}; };

View File

@ -17,7 +17,7 @@ const subscribeHook = (z, bundle) => {
const options = { const options = {
url: url, url: url,
method: 'POST', method: 'POST',
body: JSON.stringify(data) body: data,
}; };
// You may return a promise or a normal data structure from any perform method. // You may return a promise or a normal data structure from any perform method.
@ -90,7 +90,7 @@ module.exports = {
noun: 'Order', noun: 'Order',
display: { display: {
label: 'New Order', label: 'New Order',
description: 'Trigger when a new order with action is done in Dolibarr.' description: 'Triggers when a new order with action is done in Dolibarr.'
}, },
// `operation` is where the business logic goes. // `operation` is where the business logic goes.
@ -101,6 +101,7 @@ module.exports = {
inputFields: [ inputFields: [
{ {
key: 'action', key: 'action',
required: true,
type: 'string', type: 'string',
helpText: 'Which action of order this should trigger on.', helpText: 'Which action of order this should trigger on.',
choices: { choices: {
@ -136,11 +137,11 @@ module.exports = {
// outputFields: () => { return []; } // outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields // Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [ outputFields: [
{key: 'id', label: 'ID'}, {key: 'id', type: "integer", label: 'ID'},
{key: 'createdAt', label: 'Created At'}, {key: 'createdAt', type: "integer", label: 'Created At'},
{key: 'name', label: 'Name'}, {key: 'name', label: 'Name'},
{key: 'directions', label: 'Directions'}, {key: 'directions', label: 'Directions'},
{key: 'authorId', label: 'Author ID'}, {key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'module', label: 'Module'}, {key: 'module', label: 'Module'},
{key: 'action', label: 'Action'} {key: 'action', label: 'Action'}
] ]

View File

@ -17,7 +17,7 @@ const subscribeHook = (z, bundle) => {
const options = { const options = {
url: url, url: url,
method: 'POST', method: 'POST',
body: JSON.stringify(data) body: data,
}; };
// You may return a promise or a normal data structure from any perform method. // You may return a promise or a normal data structure from any perform method.
@ -112,7 +112,7 @@ module.exports = {
noun: 'Thirdparty', noun: 'Thirdparty',
display: { display: {
label: 'New Thirdparty', label: 'New Thirdparty',
description: 'Trigger when a new thirdpaty action is done in Dolibarr.' description: 'Triggers when a new thirdpaty action is done in Dolibarr.'
}, },
// `operation` is where the business logic goes. // `operation` is where the business logic goes.
@ -123,6 +123,7 @@ module.exports = {
inputFields: [ inputFields: [
{ {
key: 'action', key: 'action',
required: true,
type: 'string', type: 'string',
helpText: 'Which action of thirdparty this should trigger on.', helpText: 'Which action of thirdparty this should trigger on.',
choices: { choices: {
@ -159,12 +160,12 @@ module.exports = {
// outputFields: () => { return []; } // outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields // Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [ outputFields: [
{key: 'id', label: 'ID'}, {key: 'id', type: "integer", label: 'ID'},
{key: 'createdAt', label: 'Created At'}, {key: 'createdAt', label: 'Created At'},
{key: 'name', label: 'Name'}, {key: 'name', label: 'Name'},
{key: 'name_alias', label: 'Name alias'}, {key: 'name_alias', label: 'Name alias'},
{key: 'firstname', label: 'Firstame'}, {key: 'firstname', label: 'Firstname'},
{key: 'authorId', label: 'Author ID'}, {key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'action', label: 'Action'}, {key: 'action', label: 'Action'},
{key: 'client', label: 'Customer/Prospect 0/1/2/3'}, {key: 'client', label: 'Customer/Prospect 0/1/2/3'},
{key: 'fournisseur', label: 'Supplier 0/1'}, {key: 'fournisseur', label: 'Supplier 0/1'},

View File

@ -0,0 +1,237 @@
const subscribeHook = (z, bundle) => {
// `z.console.log()` is similar to `console.log()`.
z.console.log('suscribing hook!');
// bundle.targetUrl has the Hook URL this app should call when an action is created.
const data = {
url: bundle.targetUrl,
event: bundle.event,
module: 'ticket',
action: bundle.inputData.action
};
const url = bundle.authData.url + '/api/index.php/zapierapi/hook';
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: url,
method: 'POST',
body: data,
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const unsubscribeHook = (z, bundle) => {
// bundle.subscribeData contains the parsed response JSON from the subscribe
// request made initially.
z.console.log('unsuscribing hook!');
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id,
method: 'DELETE',
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const getTicket = (z, bundle) => {
// bundle.cleanedRequest will include the parsed JSON object (if it's not a
// test poll) and also a .querystring property with the URL's query string.
const ticket = {
id: bundle.cleanedRequest.id,
track_id: bundle.cleanedRequest.track_id,
subject: bundle.cleanedRequest.subject,
message: bundle.cleanedRequest.message,
lastname: bundle.cleanedRequest.lastname,
firstname: bundle.cleanedRequest.firstname,
address: bundle.cleanedRequest.address,
zip: bundle.cleanedRequest.zip,
town: bundle.cleanedRequest.town,
email_from: bundle.cleanedRequest.email_from,
login: bundle.cleanedRequest.login,
authorId: bundle.cleanedRequest.authorId,
createdAt: bundle.cleanedRequest.createdAt,
action: bundle.cleanedRequest.action
};
return [ticket];
};
const getFallbackRealTicket = (z, bundle) => {
// For the test poll, you should get some real data, to aid the setup process.
const module = bundle.inputData.module;
const options = {
url: bundle.authData.url + '/api/index.php/tickets/0',
};
return z.request(options).then((response) => [JSON.parse(response.content)]);
};
// const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices',
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// const getModulesChoices = () => {
// return {
// orders: "Order",
// invoices: "Invoice",
// thirdparties: "Thirdparty",
// users: "User",
// tickets: "Ticket",
// contacts: "Contacts"
// };
// };
// const getActionsChoices = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module;
// const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`,
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// We recommend writing your triggers separate like this and rolling them
// into the App definition at the end.
module.exports = {
key: 'ticket',
// You'll want to provide some helpful display labels and descriptions
// for tickets. Zapier will put them into the UX.
noun: 'Ticket',
display: {
label: 'New Ticket',
description: 'Triggers when a new ticket action is done in Dolibarr.'
},
// `operation` is where the business logic goes.
operation: {
// `inputFields` can define the fields a ticket could provide,
// we'll pass them in as `bundle.inputData` later.
inputFields: [
{
key: 'action',
type: 'string',
required: true,
helpText: 'Which action of ticket this should trigger on.',
choices: {
create: "Create",
modify: "Modify",
validate: "Validate",
}
}
],
type: 'hook',
performSubscribe: subscribeHook,
performUnsubscribe: unsubscribeHook,
perform: getTicket,
performList: getFallbackRealTicket,
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
track_id: 'Xaz123er',
subject: 'Subject',
message: 'Message',
createdAt: 1472069465,
lastname: 'DOE',
firstname: 'John',
email: 'john@doe.com',
address: 'Park Avenue',
zip: '12345',
town: 'NEW-YORK',
email_from: 'doe.john@example;com',
authorId: 1,
action: 'create'
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{
key: 'id',
type: "integer",
label: 'ID'
},
{
key: 'track_id',
type: "string",
label: 'TrackID'
},
{
key: 'subject',
type: "string",
label: 'Subject'
},
{
key: 'message',
type: "string",
label: 'Message'
},
{
key: 'createdAt',
type: "integer",
label: 'Created At'
},
{
key: 'lastname',
label: 'Lastname'
},
{
key: 'firstname',
label: 'Firstname'
},
{
key: 'email',
label: 'Email'
},
{
key: 'address',
label: 'Address'
},
{
key: 'zip',
label: 'Zip'
},
{
key: 'town',
label: 'Town'
},
{
key: 'email_from',
type: 'string',
label: 'Email from'
},
{
key: 'authorId',
type: "integer",
label: 'Author ID'
},
{
key: 'action',
type: 'string',
label: 'Action'
}
]
}
};

View File

@ -0,0 +1,177 @@
const subscribeHook = (z, bundle) => {
// `z.console.log()` is similar to `console.log()`.
z.console.log('suscribing hook!');
// bundle.targetUrl has the Hook URL this app should call when an action is created.
const data = {
url: bundle.targetUrl,
event: bundle.event,
module: 'user',
action: bundle.inputData.action
};
const url = bundle.authData.url + '/api/index.php/zapierapi/hook';
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: url,
method: 'POST',
body: data,
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const unsubscribeHook = (z, bundle) => {
// bundle.subscribeData contains the parsed response JSON from the subscribe
// request made initially.
z.console.log('unsuscribing hook!');
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id,
method: 'DELETE',
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const getUser = (z, bundle) => {
// bundle.cleanedRequest will include the parsed JSON object (if it's not a
// test poll) and also a .querystring property with the URL's query string.
const user = {
id: bundle.cleanedRequest.id,
lastname: bundle.cleanedRequest.lastname,
firstname: bundle.cleanedRequest.firstname,
address: bundle.cleanedRequest.address,
zip: bundle.cleanedRequest.zip,
town: bundle.cleanedRequest.town,
email: bundle.cleanedRequest.email,
login: bundle.cleanedRequest.login,
authorId: bundle.cleanedRequest.authorId,
createdAt: bundle.cleanedRequest.createdAt,
action: bundle.cleanedRequest.action
};
return [user];
};
const getFallbackRealUser = (z, bundle) => {
// For the test poll, you should get some real data, to aid the setup process.
const module = bundle.inputData.module;
const options = {
url: bundle.authData.url + '/api/index.php/users/0',
};
return z.request(options).then((response) => [JSON.parse(response.content)]);
};
// const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices',
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// const getModulesChoices = () => {
// return {
// orders: "Order",
// invoices: "Invoice",
// thirdparties: "Thirdparty",
// users: "User",
// contacts: "Contacts"
// };
// };
// const getActionsChoices = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module;
// const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`,
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// We recommend writing your triggers separate like this and rolling them
// into the App definition at the end.
module.exports = {
key: 'user',
// You'll want to provide some helpful display labels and descriptions
// for users. Zapier will put them into the UX.
noun: 'User',
display: {
label: 'New User',
description: 'Triggers when a new user action is done in Dolibarr.'
},
// `operation` is where the business logic goes.
operation: {
// `inputFields` can define the fields a user could provide,
// we'll pass them in as `bundle.inputData` later.
inputFields: [
{
key: 'action',
required: true,
type: 'string',
helpText: 'Which action of user this should trigger on.',
choices: {
create: "Create",
modify: "Modify",
validate: "Validate",
}
}
],
type: 'hook',
performSubscribe: subscribeHook,
performUnsubscribe: unsubscribeHook,
perform: getUser,
performList: getFallbackRealUser,
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
createdAt: 1472069465,
lastname: 'DOE',
firstname: 'John',
email: 'john@doe.com',
address: 'Park Avenue',
zip: '12345',
town: 'NEW-YORK',
login: 'doe.john',
authorId: 1,
action: 'create'
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{key: 'id', type: "integer", label: 'ID'},
{key: 'createdAt', type: "integer", label: 'Created At'},
{key: 'lastname', label: 'Lastname'},
{key: 'firstname', label: 'Firstname'},
{key: 'email', label: 'Email'},
{key: 'address', label: 'Address'},
{key: 'zip', label: 'Zip'},
{key: 'town', label: 'Town'},
{key: 'login', label: 'Login'},
{key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'action', label: 'Action'}
]
}
};

View File

@ -2306,14 +2306,16 @@ class Adherent extends CommonObject
* Used to build previews or test instances. * Used to build previews or test instances.
* id must be 0 if object instance is a specimen. * id must be 0 if object instance is a specimen.
* *
* @return void * @return int
*/ */
public function initAsSpecimen() public function initAsSpecimen()
{ {
global $user, $langs; global $user, $langs;
$now = dol_now();
// Initialise parametres // Initialise parametres
$this->id = 0; $this->id = 0;
$this->entity = 1;
$this->specimen = 1; $this->specimen = 1;
$this->civility_id = 0; $this->civility_id = 0;
$this->lastname = 'DOLIBARR'; $this->lastname = 'DOLIBARR';
@ -2330,24 +2332,30 @@ class Adherent extends CommonObject
$this->country = 'France'; $this->country = 'France';
$this->morphy = 'mor'; $this->morphy = 'mor';
$this->email = 'specimen@specimen.com'; $this->email = 'specimen@specimen.com';
$this->socialnetworks = array('skype' => 'skypepseudo', 'twitter' => 'twitterpseudo', 'facebook' => 'facebookpseudo', 'linkedin' => 'linkedinpseudo'); $this->socialnetworks = array(
'skype' => 'skypepseudo',
'twitter' => 'twitterpseudo',
'facebook' => 'facebookpseudo',
'linkedin' => 'linkedinpseudo',
);
$this->phone = '0999999999'; $this->phone = '0999999999';
$this->phone_perso = '0999999998'; $this->phone_perso = '0999999998';
$this->phone_mobile = '0999999997'; $this->phone_mobile = '0999999997';
$this->note_private = 'No comment'; $this->note_public = 'This is a public note';
$this->birth = time(); $this->note_private = 'This is a private note';
$this->birth = $now;
$this->photo = ''; $this->photo = '';
$this->public = 1; $this->public = 1;
$this->statut = 0; $this->statut = 0;
$this->datefin = time(); $this->datefin = $now;
$this->datevalid = time(); $this->datevalid = $now;
$this->typeid = 1; // Id type adherent $this->typeid = 1; // Id type adherent
$this->type = 'Type adherent'; // Libelle type adherent $this->type = 'Type adherent'; // Libelle type adherent
$this->need_subscription = 0; $this->need_subscription = 0;
$this->first_subscription_date = time(); $this->first_subscription_date = $now;
$this->first_subscription_date_start = $this->first_subscription_date; $this->first_subscription_date_start = $this->first_subscription_date;
$this->first_subscription_date_end = dol_time_plus_duree($this->first_subscription_date_start, 1, 'y'); $this->first_subscription_date_end = dol_time_plus_duree($this->first_subscription_date_start, 1, 'y');
$this->first_subscription_amount = 10; $this->first_subscription_amount = 10;
@ -2356,6 +2364,7 @@ class Adherent extends CommonObject
$this->last_subscription_date_start = $this->first_subscription_date; $this->last_subscription_date_start = $this->first_subscription_date;
$this->last_subscription_date_end = dol_time_plus_duree($this->last_subscription_date_start, 1, 'y'); $this->last_subscription_date_end = dol_time_plus_duree($this->last_subscription_date_start, 1, 'y');
$this->last_subscription_amount = 10; $this->last_subscription_amount = 10;
return 1;
} }

View File

@ -67,12 +67,16 @@ class Members extends DolibarrApi
} }
$member = new Adherent($this->db); $member = new Adherent($this->db);
if ($id == 0) {
$result = $member->initAsSpecimen();
} else {
$result = $member->fetch($id); $result = $member->fetch($id);
}
if (!$result) { if (!$result) {
throw new RestException(404, 'member not found'); throw new RestException(404, 'member not found');
} }
if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) { if (!DolibarrApi::_checkAccessToResource('adherent', $member->id) && $id > 0) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
} }

View File

@ -221,11 +221,9 @@ class DolibarrApi
} }
} }
if (!empty($object->thirdparty) && is_object($object->thirdparty)) if (!empty($object->thirdparty) && is_object($object->thirdparty)) {
{
$this->_cleanObjectDatas($object->thirdparty); $this->_cleanObjectDatas($object->thirdparty);
} }
return $object; return $object;
} }

View File

@ -229,9 +229,7 @@ class Documents extends DolibarrApi
if ($result <= 0) { if ($result <= 0) {
throw new RestException(500, 'Error generating document'); throw new RestException(500, 'Error generating document');
} }
} } else {
else
{
throw new RestException(403, 'Generation not available for this modulepart'); throw new RestException(403, 'Generation not available for this modulepart');
} }
@ -277,6 +275,8 @@ class Documents extends DolibarrApi
} }
$id = (empty($id) ? 0 : $id); $id = (empty($id) ? 0 : $id);
$recursive = 0;
$type = 'files';
if ($modulepart == 'societe' || $modulepart == 'thirdparty') if ($modulepart == 'societe' || $modulepart == 'thirdparty')
{ {
@ -474,11 +474,27 @@ class Documents extends DolibarrApi
} }
$upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref); $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
} elseif ($modulepart == 'ecm') {
throw new RestException(500, 'Modulepart Ecm not implemented yet.');
// // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
// if (!DolibarrApiAccess::$user->rights->ecm->read) {
// throw new RestException(401);
// }
// // $object = new EcmDirectory($this->db);
// // $result = $object->fetch($ref);
// // if (!$result) {
// // throw new RestException(404, 'EcmDirectory not found');
// // }
// $upload_dir = $conf->ecm->dir_output;
// $type = 'all';
// $recursive = 0;
} else { } else {
throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.'); throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
} }
$filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
if (empty($filearray)) { if (empty($filearray)) {
throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.'); throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
} }
@ -592,9 +608,7 @@ class Documents extends DolibarrApi
{ {
$tmpreldir = dol_sanitizeFileName($object->project->ref).'/'; $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
} }
} } else {
else
{
throw new RestException(500, 'Error while fetching Task '.$ref); throw new RestException(500, 'Error while fetching Task '.$ref);
} }
} }
@ -619,10 +633,8 @@ class Documents extends DolibarrApi
$modulepart = 'propale'; $modulepart = 'propale';
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
$object = new Propal($this->db); $object = new Propal($this->db);
} } else {
// TODO Implement additional moduleparts // TODO Implement additional moduleparts
else
{
throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.'); throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
} }
@ -660,9 +672,7 @@ class Documents extends DolibarrApi
{ {
throw new RestException(500, 'This value of modulepart does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.'); throw new RestException(500, 'This value of modulepart does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
} }
} } else {
else
{
if ($modulepart == 'invoice') $modulepart = 'facture'; if ($modulepart == 'invoice') $modulepart = 'facture';
if ($modulepart == 'member') $modulepart = 'adherent'; if ($modulepart == 'member') $modulepart = 'adherent';
@ -700,20 +710,16 @@ class Documents extends DolibarrApi
} }
$fhandle = @fopen($destfiletmp, 'w'); $fhandle = @fopen($destfiletmp, 'w');
if ($fhandle) if ($fhandle) {
{
$nbofbyteswrote = fwrite($fhandle, $newfilecontent); $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
fclose($fhandle); fclose($fhandle);
@chmod($destfiletmp, octdec($conf->global->MAIN_UMASK)); @chmod($destfiletmp, octdec($conf->global->MAIN_UMASK));
} } else {
else
{
throw new RestException(500, "Failed to open file '".$destfiletmp."' for write"); throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
} }
$result = dol_move($destfiletmp, $destfile, 0, $overwriteifexists, 1); $result = dol_move($destfiletmp, $destfile, 0, $overwriteifexists, 1);
if (!$result) if (!$result) {
{
throw new RestException(500, "Failed to move file into '".$destfile."'"); throw new RestException(500, "Failed to move file into '".$destfile."'");
} }

View File

@ -524,7 +524,7 @@ class ActionComm extends CommonObject
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if ($resql) if ($resql)
{ {
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."actioncomm", "id"); $this->ref =$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."actioncomm", "id");
// Now insert assigned users // Now insert assigned users
if (!$error) if (!$error)

View File

@ -56,9 +56,16 @@ class PaymentVarious extends CommonObject
*/ */
public $ref; public $ref;
/**
* @var int timestamp
*/
public $tms; public $tms;
public $datep; public $datep;
public $datev; public $datev;
/**
* @var int sens of operation
*/
public $sens; public $sens;
public $amount; public $amount;
public $type_payment; public $type_payment;
@ -90,6 +97,16 @@ class PaymentVarious extends CommonObject
*/ */
public $fk_bank; public $fk_bank;
/**
* @var int transaction category
*/
public $categorie_transaction;
/**
* @var int Account ID
*/
public $accountid;
/** /**
* @var int ID * @var int ID
*/ */

View File

@ -8,7 +8,7 @@
* Copyright (C) 2013-2016 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2013-2016 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr> * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
* Copyright (C) 2018-2019 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2019 Josep Lluís Amador <joseplluis@lliuretic.cat> * Copyright (C) 2019 Josep Lluís Amador <joseplluis@lliuretic.cat>
* Copyright (C) 2020 Open-Dsi <support@open-dsi.fr> * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
* *
@ -178,15 +178,15 @@ if (empty($reshook))
$object->entity = (GETPOSTISSET('entity') ?GETPOST('entity', 'int') : $conf->entity); $object->entity = (GETPOSTISSET('entity') ?GETPOST('entity', 'int') : $conf->entity);
$object->socid = GETPOST("socid", 'int'); $object->socid = GETPOST("socid", 'int');
$object->lastname = GETPOST("lastname", 'alpha'); $object->lastname = (string) GETPOST("lastname", 'alpha');
$object->firstname = GETPOST("firstname", 'alpha'); $object->firstname = (string) GETPOST("firstname", 'alpha');
$object->civility_code = GETPOST("civility_code", 'alpha'); $object->civility_code = (string) GETPOST("civility_code", 'alpha');
$object->poste = GETPOST("poste", 'alpha'); $object->poste = (string) GETPOST("poste", 'alpha');
$object->address = GETPOST("address", 'alpha'); $object->address = (string) GETPOST("address", 'alpha');
$object->zip = GETPOST("zipcode", 'alpha'); $object->zip = (string) GETPOST("zipcode", 'alpha');
$object->town = GETPOST("town", 'alpha'); $object->town = (string) GETPOST("town", 'alpha');
$object->country_id = GETPOST("country_id", 'int'); $object->country_id = (int) GETPOST("country_id", 'int');
$object->state_id = GETPOST("state_id", 'int'); $object->state_id = (int) GETPOST("state_id", 'int');
//$object->jabberid = GETPOST("jabberid", 'alpha'); //$object->jabberid = GETPOST("jabberid", 'alpha');
//$object->skype = GETPOST("skype", 'alpha'); //$object->skype = GETPOST("skype", 'alpha');
//$object->twitter = GETPOST("twitter", 'alpha'); //$object->twitter = GETPOST("twitter", 'alpha');
@ -196,22 +196,22 @@ if (empty($reshook))
if (!empty($conf->socialnetworks->enabled)) { if (!empty($conf->socialnetworks->enabled)) {
foreach ($socialnetworks as $key => $value) { foreach ($socialnetworks as $key => $value) {
if (GETPOSTISSET($key) && GETPOST($key, 'alphanohtml') != '') { if (GETPOSTISSET($key) && GETPOST($key, 'alphanohtml') != '') {
$object->socialnetworks[$key] = GETPOST($key, 'alphanohtml'); $object->socialnetworks[$key] = (string) GETPOST($key, 'alphanohtml');
} }
} }
} }
$object->email = GETPOST("email", 'alpha'); $object->email = (string) GETPOST("email", 'alpha');
$object->no_email = GETPOST("no_email", "int"); $object->no_email = GETPOST("no_email", "int");
$object->phone_pro = GETPOST("phone_pro", 'alpha'); $object->phone_pro = (string) GETPOST("phone_pro", 'alpha');
$object->phone_perso = GETPOST("phone_perso", 'alpha'); $object->phone_perso = (string) GETPOST("phone_perso", 'alpha');
$object->phone_mobile = GETPOST("phone_mobile", 'alpha'); $object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha');
$object->fax = GETPOST("fax", 'alpha'); $object->fax = (string) GETPOST("fax", 'alpha');
$object->priv = GETPOST("priv", 'int'); $object->priv = GETPOST("priv", 'int');
$object->note_public = GETPOST("note_public", 'restricthtml'); $object->note_public = (string) GETPOST("note_public", 'restricthtml');
$object->note_private = GETPOST("note_private", 'restricthtml'); $object->note_private = (string) GETPOST("note_private", 'restricthtml');
$object->roles = GETPOST("roles", 'array'); $object->roles = GETPOST("roles", 'array');
$object->statut = 1; //Defult status to Actif $object->statut = 1; //Default status to Actif
// Note: Correct date should be completed with location to have exact GM time of birth. // Note: Correct date should be completed with location to have exact GM time of birth.
$object->birthday = dol_mktime(0, 0, 0, GETPOST("birthdaymonth", 'int'), GETPOST("birthdayday", 'int'), GETPOST("birthdayyear", 'int')); $object->birthday = dol_mktime(0, 0, 0, GETPOST("birthdaymonth", 'int'), GETPOST("birthdayday", 'int'), GETPOST("birthdayyear", 'int'));
@ -225,9 +225,9 @@ if (empty($reshook))
$action = 'create'; $action = 'create';
} }
if (!GETPOST("lastname")) if (!GETPOST("lastname")) {
{ $error++;
$error++; $errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Lastname").' / '.$langs->transnoentities("Label")); $errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Lastname").' / '.$langs->transnoentities("Label"));
$action = 'create'; $action = 'create';
} }
@ -236,7 +236,8 @@ if (empty($reshook))
$id = $object->create($user); $id = $object->create($user);
if ($id <= 0) if ($id <= 0)
{ {
$error++; $errors = array_merge($errors, ($object->error ? array($object->error) : $object->errors)); $error++;
$errors = array_merge($errors, ($object->error ? array($object->error) : $object->errors));
$action = 'create'; $action = 'create';
} else { } else {
// Categories association // Categories association
@ -278,14 +279,12 @@ if (empty($reshook))
$result = $object->fetch($id); $result = $object->fetch($id);
$object->oldcopy = clone $object; $object->oldcopy = clone $object;
$object->old_lastname = GETPOST("old_lastname"); $object->old_lastname = (string) GETPOST("old_lastname", 'alpha');
$object->old_firstname = GETPOST("old_firstname"); $object->old_firstname = (string) GETPOST("old_firstname", 'alpha');
$result = $object->delete(); $result = $object->delete();
if ($result > 0) if ($result > 0) {
{ if ($backtopage) {
if ($backtopage)
{
header("Location: ".$backtopage); header("Location: ".$backtopage);
exit; exit;
} else { } else {
@ -360,22 +359,22 @@ if (empty($reshook))
$object->oldcopy = clone $object; $object->oldcopy = clone $object;
$object->old_lastname = GETPOST("old_lastname", 'alpha'); $object->old_lastname = (string) GETPOST("old_lastname", 'alpha');
$object->old_firstname = GETPOST("old_firstname", 'alpha'); $object->old_firstname = (string) GETPOST("old_firstname", 'alpha');
$object->socid = GETPOST("socid", 'int'); $object->socid = GETPOST("socid", 'int');
$object->lastname = GETPOST("lastname", 'alpha'); $object->lastname = (string) GETPOST("lastname", 'alpha');
$object->firstname = GETPOST("firstname", 'alpha'); $object->firstname = (string) GETPOST("firstname", 'alpha');
$object->civility_code = GETPOST("civility_code", 'alpha'); $object->civility_code = (string) GETPOST("civility_code", 'alpha');
$object->poste = GETPOST("poste", 'alpha'); $object->poste = (string) GETPOST("poste", 'alpha');
$object->address = GETPOST("address", 'alpha'); $object->address = (string) GETPOST("address", 'alpha');
$object->zip = GETPOST("zipcode", 'alpha'); $object->zip = (string) GETPOST("zipcode", 'alpha');
$object->town = GETPOST("town", 'alpha'); $object->town = (string) GETPOST("town", 'alpha');
$object->state_id = GETPOST("state_id", 'int'); $object->state_id = GETPOST("state_id", 'int');
$object->country_id = GETPOST("country_id", 'int'); $object->country_id = GETPOST("country_id", 'int');
$object->email = GETPOST("email", 'alpha'); $object->email = (string) GETPOST("email", 'alpha');
$object->no_email = GETPOST("no_email", "int"); $object->no_email = GETPOST("no_email", "int");
//$object->jabberid = GETPOST("jabberid", 'alpha'); //$object->jabberid = GETPOST("jabberid", 'alpha');
//$object->skype = GETPOST("skype", 'alpha'); //$object->skype = GETPOST("skype", 'alpha');
@ -386,17 +385,17 @@ if (empty($reshook))
if (!empty($conf->socialnetworks->enabled)) { if (!empty($conf->socialnetworks->enabled)) {
foreach ($socialnetworks as $key => $value) { foreach ($socialnetworks as $key => $value) {
if (GETPOSTISSET($key) && GETPOST($key, 'alphanohtml') != '') { if (GETPOSTISSET($key) && GETPOST($key, 'alphanohtml') != '') {
$object->socialnetworks[$key] = GETPOST($key, 'alphanohtml'); $object->socialnetworks[$key] = (string) GETPOST($key, 'alphanohtml');
} }
} }
} }
$object->phone_pro = GETPOST("phone_pro", 'alpha'); $object->phone_pro = (string) GETPOST("phone_pro", 'alpha');
$object->phone_perso = GETPOST("phone_perso", 'alpha'); $object->phone_perso = (string) GETPOST("phone_perso", 'alpha');
$object->phone_mobile = GETPOST("phone_mobile", 'alpha'); $object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha');
$object->fax = GETPOST("fax", 'alpha'); $object->fax = (string) GETPOST("fax", 'alpha');
$object->priv = GETPOST("priv", 'int'); $object->priv = (string) GETPOST("priv", 'int');
$object->note_public = GETPOST("note_public", 'restricthtml'); $object->note_public = (string) GETPOST("note_public", 'restricthtml');
$object->note_private = GETPOST("note_private", 'restricthtml'); $object->note_private = (string) GETPOST("note_private", 'restricthtml');
$object->roles = GETPOST("roles", 'array'); $object->roles = GETPOST("roles", 'array');
// Fill array 'array_options' with data from add form // Fill array 'array_options' with data from add form

View File

@ -85,8 +85,28 @@ class InterfaceZapierTriggers extends DolibarrTriggers
switch ($action) { switch ($action) {
// Users // Users
//case 'USER_CREATE': case 'USER_CREATE':
//case 'USER_MODIFY': $resql = $this->db->query($sql);
// TODO voir comment regrouper les webhooks en un post
while ($resql && $obj = $this->db->fetch_array($resql)) {
$cleaned = cleanObjectDatas(dol_clone($object));
$json = json_encode($cleaned);
// call the zapierPostWebhook() function
zapierPostWebhook($obj['url'], $json);
}
$logtriggeraction = true;
break;
case 'USER_MODIFY':
$resql = $this->db->query($sql);
// TODO voir comment regrouper les webhooks en un post
while ($resql && $obj = $this->db->fetch_array($resql)) {
$cleaned = cleanObjectDatas(dol_clone($object));
$json = json_encode($cleaned);
// call the zapierPostWebhook() function
zapierPostWebhook($obj['url'], $json);
}
$logtriggeraction = true;
break;
//case 'USER_NEW_PASSWORD': //case 'USER_NEW_PASSWORD':
//case 'USER_ENABLEDISABLE': //case 'USER_ENABLEDISABLE':
//case 'USER_DELETE': //case 'USER_DELETE':
@ -124,6 +144,12 @@ class InterfaceZapierTriggers extends DolibarrTriggers
//case 'USERGROUP_MODIFY': //case 'USERGROUP_MODIFY':
//case 'USERGROUP_DELETE': //case 'USERGROUP_DELETE':
// Categories
// case 'CATEGORY_CREATE':
// case 'CATEGORY_MODIFY':
// case 'CATEGORY_DELETE':
// case 'CATEGORY_SET_MULTILANGS':
// Companies // Companies
case 'COMPANY_CREATE': case 'COMPANY_CREATE':
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
@ -305,12 +331,6 @@ class InterfaceZapierTriggers extends DolibarrTriggers
// case 'MEMBER_RESILIATE': // case 'MEMBER_RESILIATE':
// case 'MEMBER_DELETE': // case 'MEMBER_DELETE':
// Categories
// case 'CATEGORY_CREATE':
// case 'CATEGORY_MODIFY':
// case 'CATEGORY_DELETE':
// case 'CATEGORY_SET_MULTILANGS':
// Projects // Projects
// case 'PROJECT_CREATE': // case 'PROJECT_CREATE':
// case 'PROJECT_MODIFY': // case 'PROJECT_MODIFY':
@ -325,6 +345,21 @@ class InterfaceZapierTriggers extends DolibarrTriggers
// case 'TASK_TIMESPENT_CREATE': // case 'TASK_TIMESPENT_CREATE':
// case 'TASK_TIMESPENT_MODIFY': // case 'TASK_TIMESPENT_MODIFY':
// case 'TASK_TIMESPENT_DELETE': // case 'TASK_TIMESPENT_DELETE':
case 'TICKET_CREATE':
$resql = $this->db->query($sql);
// TODO voir comment regrouper les webhooks en un post
while ($resql && $obj = $this->db->fetch_array($resql)) {
$cleaned = cleanObjectDatas(dol_clone($object));
$json = json_encode($cleaned);
// call the zapierPostWebhook() function
zapierPostWebhook($obj['url'], $json);
}
$logtriggeraction = true;
break;
// case 'TICKET_MODIFY':
// break;
// case 'TICKET_DELETE':
// break;
// Shipping // Shipping
// case 'SHIPPING_CREATE': // case 'SHIPPING_CREATE':
@ -453,7 +488,7 @@ function cleanObjectDatas($toclean)
/** /**
* Clean sensible object datas * Clean sensible object datas
* *
* @param object $toclean Object to clean * @param Object $toclean Object to clean
* @return Object Object with cleaned properties * @return Object Object with cleaned properties
*/ */
function cleanAgendaEventsDatas($toclean) function cleanAgendaEventsDatas($toclean)

View File

@ -2,6 +2,7 @@
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr> /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
* Copyright (C) 2018 Pierre Chéné <pierre.chene44@gmail.com> * Copyright (C) 2018 Pierre Chéné <pierre.chene44@gmail.com>
* Copyright (C) 2019 Cedric Ancelin <icedo.anc@gmail.com> * Copyright (C) 2019 Cedric Ancelin <icedo.anc@gmail.com>
* Copyright (C) 2020 Frédéric France <frederic.france@netlogic.fr>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -68,7 +69,7 @@ class Thirdparties extends DolibarrApi
* Return an array with thirdparty informations * Return an array with thirdparty informations
* *
* @param int $id Id of third party to load * @param int $id Id of third party to load
* @return array|mixed data without useless information * @return Object Cleaned Societe object
* *
* @throws RestException * @throws RestException
*/ */
@ -83,7 +84,7 @@ class Thirdparties extends DolibarrApi
* Return an array with thirdparty informations * Return an array with thirdparty informations
* *
* @param string $email Email of third party to load * @param string $email Email of third party to load
* @return array|mixed data without useless information * @return Object Cleaned Societe object
* *
* @url GET email/{email} * @url GET email/{email}
* *
@ -100,7 +101,7 @@ class Thirdparties extends DolibarrApi
* Return an array with thirdparty informations * Return an array with thirdparty informations
* *
* @param string $barcode Barcode of third party to load * @param string $barcode Barcode of third party to load
* @return array|mixed data without useless information * @return Object Cleaned Societe object
* *
* @url GET barcode/{barcode} * @url GET barcode/{barcode}
* *
@ -154,9 +155,9 @@ class Thirdparties extends DolibarrApi
$sql .= " AND t.fk_stcomm = st.id"; $sql .= " AND t.fk_stcomm = st.id";
if ($mode == 1) $sql .= " AND t.client IN (1, 3)"; if ($mode == 1) $sql .= " AND t.client IN (1, 3)";
if ($mode == 2) $sql .= " AND t.client IN (2, 3)"; elseif ($mode == 2) $sql .= " AND t.client IN (2, 3)";
if ($mode == 3) $sql .= " AND t.client IN (0)"; elseif ($mode == 3) $sql .= " AND t.client IN (0)";
if ($mode == 4) $sql .= " AND t.fournisseur IN (1)"; elseif ($mode == 4) $sql .= " AND t.fournisseur IN (1)";
// Select thirdparties of given category // Select thirdparties of given category
if ($category > 0) { if ($category > 0) {
@ -188,8 +189,7 @@ class Thirdparties extends DolibarrApi
$sql .= $this->db->order($sortfield, $sortorder); $sql .= $this->db->order($sortfield, $sortorder);
if ($limit) { if ($limit) {
if ($page < 0) if ($page < 0) {
{
$page = 0; $page = 0;
} }
$offset = $limit * $page; $offset = $limit * $page;
@ -249,7 +249,7 @@ class Thirdparties extends DolibarrApi
* *
* @param int $id Id of thirdparty to update * @param int $id Id of thirdparty to update
* @param array $request_data Datas * @param array $request_data Datas
* @return int * @return Object|boolean
*/ */
public function put($id, $request_data = null) public function put($id, $request_data = null)
{ {
@ -271,8 +271,9 @@ class Thirdparties extends DolibarrApi
$this->company->$field = $value; $this->company->$field = $value;
} }
if ($this->company->update($id, DolibarrApiAccess::$user, 1, '', '', 'update')) if ($this->company->update($id, DolibarrApiAccess::$user, 1, '', '', 'update')) {
return $this->get($id); return $this->get($id);
}
return false; return false;
} }
@ -1840,7 +1841,7 @@ class Thirdparties extends DolibarrApi
* @param string $idprof6 Prof id 6 of third party (Warning, this can return several records) * @param string $idprof6 Prof id 6 of third party (Warning, this can return several records)
* @param string $email Email of third party (Warning, this can return several records) * @param string $email Email of third party (Warning, this can return several records)
* @param string $ref_alias Name_alias of third party (Warning, this can return several records) * @param string $ref_alias Name_alias of third party (Warning, this can return several records)
* @return array|mixed data without useless information * @return Object cleaned Societe object
* *
* @throws RestException * @throws RestException
*/ */
@ -1850,8 +1851,11 @@ class Thirdparties extends DolibarrApi
if (!DolibarrApiAccess::$user->rights->societe->lire) { if (!DolibarrApiAccess::$user->rights->societe->lire) {
throw new RestException(401); throw new RestException(401);
} }
if ($rowid == 0) {
$result = $this->company->initAsSpecimen();
} else {
$result = $this->company->fetch($rowid, $ref, $ref_ext, $barcode, $idprof1, $idprof2, $idprof3, $idprof4, $idprof5, $idprof6, $email, $ref_alias); $result = $this->company->fetch($rowid, $ref, $ref_ext, $barcode, $idprof1, $idprof2, $idprof3, $idprof4, $idprof5, $idprof6, $email, $ref_alias);
}
if (!$result) { if (!$result) {
throw new RestException(404, 'Thirdparty not found'); throw new RestException(404, 'Thirdparty not found');
} }

View File

@ -3765,6 +3765,7 @@ class Societe extends CommonObject
// Initialize parameters // Initialize parameters
$this->id = 0; $this->id = 0;
$this->entity = 1;
$this->name = 'THIRDPARTY SPECIMEN '.dol_print_date($now, 'dayhourlog'); $this->name = 'THIRDPARTY SPECIMEN '.dol_print_date($now, 'dayhourlog');
$this->nom = $this->name; // For backward compatibility $this->nom = $this->name; // For backward compatibility
$this->ref_ext = 'Ref ext'; $this->ref_ext = 'Ref ext';

View File

@ -136,11 +136,14 @@ class Tickets extends DolibarrApi
} }
// Check parameters // Check parameters
if (!$id && !$track_id && !$ref) { if (($id < 0) && !$track_id && !$ref) {
throw new RestException(401, 'Wrong parameters'); throw new RestException(401, 'Wrong parameters');
} }
if ($id == 0) {
$result = $this->ticket->initAsSpecimen();
} else {
$result = $this->ticket->fetch($id, $ref, $track_id); $result = $this->ticket->fetch($id, $ref, $track_id);
}
if (!$result) { if (!$result) {
throw new RestException(404, 'Ticket not found'); throw new RestException(404, 'Ticket not found');
} }
@ -205,7 +208,6 @@ class Tickets extends DolibarrApi
$this->ticket->history = $history; $this->ticket->history = $history;
} }
if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) { if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
} }

View File

@ -197,6 +197,9 @@ class Ticket extends CommonObject
*/ */
public $notify_tiers_at_create; public $notify_tiers_at_create;
/**
* @var string msgid
*/
public $email_msgid; public $email_msgid;
public $lines; public $lines;
@ -1076,7 +1079,7 @@ class Ticket extends CommonObject
* Initialise object with example values * Initialise object with example values
* Id must be 0 if object instance is a specimen * Id must be 0 if object instance is a specimen
* *
* @return void * @return int
*/ */
public function initAsSpecimen() public function initAsSpecimen()
{ {
@ -1101,6 +1104,7 @@ class Ticket extends CommonObject
$this->date_read = ''; $this->date_read = '';
$this->date_close = ''; $this->date_close = '';
$this->tms = ''; $this->tms = '';
return 1;
} }
/** /**

View File

@ -174,8 +174,7 @@ if ($action == 'update' && !$cancel)
$result = $account->update($user); $result = $account->update($user);
if (!$result) if (!$result) {
{
setEventMessages($account->error, $account->errors, 'errors'); setEventMessages($account->error, $account->errors, 'errors');
$action = 'edit'; // Force chargement page edition $action = 'edit'; // Force chargement page edition
} else { } else {
@ -185,32 +184,28 @@ if ($action == 'update' && !$cancel)
} }
// update personal email // update personal email
if ($action == 'setpersonal_email') if ($action == 'setpersonal_email') {
{ $object->personal_email = (string) GETPOST('personal_email', 'alphanohtml');
$object->personal_email = GETPOST('personal_email');
$result = $object->update($user); $result = $object->update($user);
if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');
} }
// update personal mobile // update personal mobile
if ($action == 'setpersonal_mobile') if ($action == 'setpersonal_mobile') {
{ $object->personal_mobile = (string) GETPOST('personal_mobile', 'alphanohtml');
$object->personal_mobile = GETPOST('personal_mobile');
$result = $object->update($user); $result = $object->update($user);
if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');
} }
// update default_c_exp_tax_cat // update default_c_exp_tax_cat
if ($action == 'setdefault_c_exp_tax_cat') if ($action == 'setdefault_c_exp_tax_cat') {
{
$object->default_c_exp_tax_cat = GETPOST('default_c_exp_tax_cat', 'int'); $object->default_c_exp_tax_cat = GETPOST('default_c_exp_tax_cat', 'int');
$result = $object->update($user); $result = $object->update($user);
if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');
} }
// update default range // update default range
if ($action == 'setdefault_range') if ($action == 'setdefault_range') {
{
$object->default_range = GETPOST('default_range', 'int'); $object->default_range = GETPOST('default_range', 'int');
$result = $object->update($user); $result = $object->update($user);
if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');

View File

@ -153,13 +153,16 @@ class Users extends DolibarrApi
//if (!DolibarrApiAccess::$user->rights->user->user->lire) { //if (!DolibarrApiAccess::$user->rights->user->user->lire) {
//throw new RestException(401); //throw new RestException(401);
//} //}
if ($id == 0) {
$result = $this->useraccount->initAsSpecimen();
} else {
$result = $this->useraccount->fetch($id); $result = $this->useraccount->fetch($id);
}
if (!$result) { if (!$result) {
throw new RestException(404, 'User not found'); throw new RestException(404, 'User not found');
} }
if (!DolibarrApi::_checkAccessToResource('user', $this->useraccount->id, 'user')) { if ($id > 0 && !DolibarrApi::_checkAccessToResource('user', $this->useraccount->id, 'user')) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
} }
@ -327,9 +330,10 @@ class Users extends DolibarrApi
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
} }
foreach ($request_data as $field => $value) foreach ($request_data as $field => $value) {
{ if ($field == 'id') {
if ($field == 'id') continue; continue;
}
// The status must be updated using setstatus() because it // The status must be updated using setstatus() because it
// is not handled by the update() method. // is not handled by the update() method.
if ($field == 'statut') { if ($field == 'statut') {
@ -461,7 +465,9 @@ class Users extends DolibarrApi
$sql = "SELECT t.rowid"; $sql = "SELECT t.rowid";
$sql .= " FROM ".MAIN_DB_PREFIX."usergroup as t"; $sql .= " FROM ".MAIN_DB_PREFIX."usergroup as t";
$sql .= ' WHERE t.entity IN ('.getEntity('user').')'; $sql .= ' WHERE t.entity IN ('.getEntity('user').')';
if ($group_ids) $sql .= " AND t.rowid IN (".$group_ids.")"; if ($group_ids) {
$sql .= " AND t.rowid IN (".$group_ids.")";
}
// Add sql filters // Add sql filters
if ($sqlfilters) { if ($sqlfilters) {
if (!DolibarrApi::_checkFilters($sqlfilters)) { if (!DolibarrApi::_checkFilters($sqlfilters)) {
@ -483,13 +489,11 @@ class Users extends DolibarrApi
$result = $this->db->query($sql); $result = $this->db->query($sql);
if ($result) if ($result) {
{
$i = 0; $i = 0;
$num = $this->db->num_rows($result); $num = $this->db->num_rows($result);
$min = min($num, ($limit <= 0 ? $num : $limit)); $min = min($num, ($limit <= 0 ? $num : $limit));
while ($i < $min) while ($i < $min) {
{
$obj = $this->db->fetch_object($result); $obj = $this->db->fetch_object($result);
$group_static = new UserGroup($this->db); $group_static = new UserGroup($this->db);
if ($group_static->fetch($obj->rowid)) { if ($group_static->fetch($obj->rowid)) {
@ -681,8 +685,9 @@ class Users extends DolibarrApi
{ {
$account = array(); $account = array();
foreach (Users::$FIELDS as $field) { foreach (Users::$FIELDS as $field) {
if (!isset($data[$field])) if (!isset($data[$field])) {
throw new RestException(400, "$field field missing"); throw new RestException(400, "$field field missing");
}
$account[$field] = $data[$field]; $account[$field] = $data[$field];
} }
return $account; return $account;

File diff suppressed because it is too large Load Diff

View File

@ -93,14 +93,13 @@ class ZapierApi extends DolibarrApi
* Get list of possibles choices for module * Get list of possibles choices for module
* *
* Return an array with hook informations * Return an array with hook informations
* @param integer $id ID
* *
* @return array|mixed data * @return array data
* *
* @url GET /getmoduleschoices/ * @url GET /getmoduleschoices/
* @throws RestException * @throws RestException
*/ */
public function getModulesChoices($id) public function getModulesChoices()
{ {
if (!DolibarrApiAccess::$user->rights->zapier->read) { if (!DolibarrApiAccess::$user->rights->zapier->read) {
throw new RestException(401); throw new RestException(401);
@ -110,6 +109,7 @@ class ZapierApi extends DolibarrApi
'orders' => 'Orders', 'orders' => 'Orders',
'thirdparties' => 'Thirparties', 'thirdparties' => 'Thirparties',
'contacts' => 'Contacts', 'contacts' => 'Contacts',
'users' => 'Users',
); );
// $result = $this->hook->fetch($id); // $result = $this->hook->fetch($id);
// if (! $result ) { // if (! $result ) {
@ -244,6 +244,7 @@ class ZapierApi extends DolibarrApi
$fields = array( $fields = array(
'url', 'url',
); );
dol_syslog("API Zapier create hook receive : " . print_r($request_data, true), LOG_DEBUG);
$result = $this->validate($request_data, $fields); $result = $this->validate($request_data, $fields);
foreach ($request_data as $field => $value) { foreach ($request_data as $field => $value) {

View File

@ -126,7 +126,7 @@ class Hook extends CommonObject
), ),
'module' => array( 'module' => array(
'type' => 'varchar(128)', 'type' => 'varchar(128)',
'label' => 'Url', 'label' => 'Module',
'enabled' => 1, 'enabled' => 1,
'visible' => 1, 'visible' => 1,
'position' => 30, 'position' => 30,
@ -137,7 +137,7 @@ class Hook extends CommonObject
), ),
'action' => array( 'action' => array(
'type' => 'varchar(128)', 'type' => 'varchar(128)',
'label' => 'Url', 'label' => 'Action',
'enabled' => 1, 'enabled' => 1,
'visible' => 1, 'visible' => 1,
'position' => 30, 'position' => 30,