Creating Contact in xero from java code gives Bad Request - spring

Below are logs which i got the error while creating contact in xero as i want to create multiple contact in xero i writing the api but i got the below error if i send the same request in postman it is working properly.
<pre>com.xero.api.XeroApiException: Bad Request
com.xero.api.XeroApiExceptionHandler.execute(XeroApiExceptionHandler.java:27)
com.xero.api.client.AccountingApi.createContact(AccountingApi.java:912)
in.techchefs.anyspace.common.service.impl.XeroServiceImpl.addContactToXero(XeroServiceImpl.java:274)
Below are code for calling the Contact API
public Contact addContactToXero(User user, String currencyCode) throws IOException {
logger.info("inside xeroservise User addContactToXero---->>"+currencyCode);
ApiClient client = new ApiClient();
accountingApi = AccountingApi.getInstance(client);
Contact contact = new Contact();
contact.setIsCustomer(true);
contact.setIsSupplier(true);
String businessName = user.getFirstName() + " " + user.getLastName() + " " + user.getId();
if (user.getBusinessInfo() != null && user.getBusinessInfo().getName() != null) {
businessName = user.getBusinessInfo().getName();
}
contact.setName(businessName);
contact.setFirstName(user.getFirstName());
contact.setLastName(user.getLastName());
contact.setContactNumber(user.getPhone());
contact.setEmailAddress(user.getEmail());
List<Address> arrayOfAddress = new ArrayList<Address>();
Set<UserAddress> userAddresses = user.getAddress();
for (Iterator iterator = userAddresses.iterator(); iterator.hasNext();) {
UserAddress userAddress = (UserAddress) iterator.next();
Address address = new Address();
address.setAddressLine1(userAddress.getStreet());
address.setAddressLine2(userAddress.getSuburb());
address.setAddressType(userAddress.getAddressType() == 1 ? AddressTypeEnum.DELIVERY : AddressTypeEnum.POBOX);
address.setRegion(userAddress.getState());
address.setPostalCode(userAddress.getPostalCode());
address.setCountry(userAddress.getCountry() == null ? "" : userAddress.getCountry().getTitle());
arrayOfAddress.add(address);
}
contact.setAddresses(arrayOfAddress);
contact.setContactStatus(ContactStatusEnum.ACTIVE);
logger.info("addContactToXero by USer contact--->>"+contact);
String accessToken=getAccessToken(currencyCode);
logger.info("addContactToXero by USer accessToken--->>"+accessToken);
XeroTokenStorage token=tokenStorageService.getByCurrencode(currencyCode);
logger.info("addContactToXero by USer token.getTenantId()--->>"+token.getTenantId());
Contacts contatcsAdded = accountingApi.createContact(accessToken,token.getTenantId(),contact);
List<Contact> contatcsAddedList = contatcsAdded.getContacts();
return contatcsAddedList.get(0);
//return contatcsAdded;
}
I give the logger for contact
class Contact {
contactID: null
contactNumber: 6666
accountNumber: null
contactStatus: ACTIVE
name: Marc Verano 1
firstName: Marc
lastName: Verano
emailAddress: info#anyspaces.com
skypeUserName: null
contactPersons: []
bankAccountDetails: null
taxNumber: null
accountsReceivableTaxType: null
accountsPayableTaxType: null
addresses: []
phones: []
isSupplier: true
isCustomer: true
defaultCurrency: null
xeroNetworkKey: null
salesDefaultAccountCode: null
purchasesDefaultAccountCode: null
salesTrackingCategories: []
purchasesTrackingCategories: []
trackingCategoryName: null
trackingCategoryOption: null
paymentTerms: null
updatedDateUTC: null
contactGroups: []
website: null
brandingTheme: null
batchPayments: null
discount: null
balances: null
attachments: []
hasAttachments: null
validationErrors: []
hasValidationErrors: null
}
i got the error from java is bad request and same request if i send through postman it is working. Pls tell me some solution on that

There is a clue in your question - "if I send the same request through postman it is working" - contact name and number need to be unique, so check that you are providing unique values for these fields.
However as droopsnoot mentioned in a comment, any validation errors will be returned from the Xero API, so interrogate the response and you will probably find the reason it is occurring.

Related

Create complex argument-driven queries from AWS Lambda?

Look for // HERE IS THE PROBLEM PART sentence to find code that is the problem.
I am trying to implement AppSync using AWS Lambda (that connects to RDS Postgres server) as a data source. I want to create puKnowledgeFile query that will update my KnowledgeFile with optional arguments. If the client only provided htmlText and properties as arguments, then my update query should only update these two fields.
type Mutation {
putKnowledgeFile(
id: ID!,
htmlText: String,
plainText: String,
properties: AWSJSON
): KnowledgeFile
}
type KnowledgeFile {
id: ID!
htmlText: String!
plainText: String!
properties: AWSJSON!
lastDateTimeModified: AWSDateTime!
dateTimeCreated: AWSDateTime!
}
Here is an piece of AWS Lambda code:
exports.handler = async (event, context, callback) => {
/* Connecting to Postgres */
let data = null;
let query = ``;
let values = [];
switch (event.info.fieldName) {
case "putKnowledgeFile":
if(event.arguments.htmlText === undefined &&
event.arguments.plainText === undefined &&
event.arguments.properties === undefined) {
callback(`At least one argument except id should be provided in putKnowledgeFile request`);
}
// HERE IS THE PROBLEM PART
query += `update knowledge_file`
query += `
set `;
let index = 0;
for (let fieldName in event.arguments) {
if(arguments.hasOwnProperty(fieldName)) {
const fieldValue = event.arguments[fieldName];
if(index === 0) {
query += `${fieldName}=$${index+1}`
values.push(fieldValue);
} else {
query += `, ${fieldName}=$${index+1}`
values.push(fieldValue);
}
index++;
}
}
query += `
where knowledge_file.id = $${index+1};`;
values.push(event.arguments.id);
// HERE IS THE PROBLEM PART
break;
default:
callback(`There is no functionality to process this field: ${event.info.fieldName}`);
return;
}
let res = null;
try {
res = await client.query(query, values); // just sending created query
} catch(error) {
console.log("#client.query");
console.log(error);
}
/* DisConnecting from Postgres */
callback(null, res.rows);
};
Basically, this algorithm creates my query string through multiple string concatenations. I think it's too complicated and error-prone. Is there a way to create dynamic queries based on the presence / absence of certain arguments easily?
Just in case, here is my PostgreSQL schema:
-- main client object for clients
CREATE TABLE client (
id bigserial primary key,
full_name varchar(255)
);
-- knowledge_file
create table knowledge_file (
id bigserial primary key,
html_text text,
plain_text text,
properties jsonb,
last_date_modified timestamptz,
date_created timestamptz,
word_count varchar(50)
);
-- which client holds which knowledge file
create TABLE client_knowledge_file (
id bigserial primary key,
client_id bigint not null references client(id),
knowledge_file_id bigint not null references knowledge_file(id) unique ON DELETE CASCADE
);
I know this is not an optimum solution and might not completely answer your question but I also ran into similar problem and this is how I solved it.
I created a resolver pipeline.
In one function, I used the select statement to get the current
record.
In second function, I checked if the fields (in your case htmlText and properties) are null. If true, then use the ctx.prev.result values otherwise use the new ones).
Practical example
First resolver function:
{
"version": "2018-05-29",
"statements": [
"select id, html_text AS \"htmlText\", plain_text AS \"plainText\", properties, last_date_modified AS \"lastDateTimeModified\", date_created AS \"dateTimeCreated\" from knowledge_file where id = $ctx.args.Id"
]
}
Second resolver function:
#set($htmlText = $util.defaultIfNull($ctx.args.htmlText , $ctx.prev.result.htmlText))
#set($properties = $util.defaultIfNull($ctx.args.properties , $ctx.prev.result.properties))
{
"version": "2018-05-29",
"statements": [
"update knowledge_file set html_text = $htmlText, plain_text = $ctx.args.plainText, properties = $properties, last_date_modified = CURRENT_TIMESTAMP, date_created = CURRENT_DATE where id = $ctx.args.Id returning id, html_text AS \"htmlText\", plain_text AS \"plainText\", properties, last_date_modified AS \"lastDateTimeModified\", date_created AS \"dateTimeCreated\""
]
}

Servicestack GlobalRequestFilters populating additional user auth data into Jwt tokens

I want to add additional properties to the response when a user logs in.
When calling https://Servicestackservice/auth/credentials?userName=****&password=**** I get the below response. I want to add 2 additional values. DateFormat & TimeZone
{
"userId": "21",
"sessionId": "****",
"userName": "SystemAdmin",
"displayName": "System Admin",
"referrerUrl": null,
"bearerToken": "****",
"refreshToken": *",
"profileUrl": *",
"roles": [ View
],
"permissions": [ View
],
"responseStatus": {
"errorCode": null,
"message": null,
"stackTrace": null,
"errors": null,
"meta": null
},
"meta": null
}
I found an example from the SS forums. I had to modify it some to make it run.
From the SS docs
Modifying the Payload
Whilst only limited info is embedded in the payload by default, all matching AuthUserSession properties embedded in the token will also be populated on the Session, which you can add to the payload using the CreatePayloadFilter delegate. So if you also want to have access to when the user was registered you can add it to the payload with:
I am hoping this is how i get them into the "matching AuthUserSession"
this.GlobalRequestFilters.Add(async (req, res, requestDto) =>
{
AuthFilter.AuthResponse(req, res, requestDto);
});
public static void AuthResponse(IRequest req, IResponse res, object response)
{
var authRes = response as Authenticate;
if (authRes == null || authRes.UserName == null)
{
return;
}
var session = (CustomUserSession)req.GetSession();
if (session != null && session.UserAuthId != null)
{
//General Format for US
string dformat = "g";
using (var db = HostContext.TryResolve<IDbConnectionFactory>().Open())
{
var userAuthExt = db.Single<UserAuthExtension>(ext => ext.UserAuthId == int.Parse(session.UserAuthId));
if (userAuthExt != null)
{
dformat = userAuthExt.DateTimeFormat;
}
}
authRes.Meta = new Dictionary<string, string> {{"TimeZone", session.TimeZone}, {"DateFormat", dformat}};
}
}
Adding this to try to get the JWT tokens to hold the new data. Examining the payload i can see the 2 new values are added to the list.
new JwtAuthProvider(AppSettings)
{
CreatePayloadFilter = (payload, session) =>
{
if (session != null && session.UserAuthId != null)
{
//General Format for US
string dformat = "g";
using (var db = HostContext.TryResolve<IDbConnectionFactory>().Open())
{
var userAuthExt = db.Single<UserAuthExtension>(ext => ext.UserAuthId == int.Parse(session.UserAuthId));
if (userAuthExt != null)
{
dformat = userAuthExt.DateTimeFormat;
}
}
payload["TimeZone"] = ((AuthUserSession) session).TimeZone;
payload["DateFormat"] = dformat;
}
},
You should link to the docs you're referring to, which I believe is ServiceStack's JWT Modifying the Payload docs. Although it's not clear which example in the Customer Forums you're referring to.
It's also not clear what the question is, I'm assuming it's this statement:
When calling /auth/credentials?userName=****&password=**** I do not see the new values.
Where exactly are you expecting these values? If you're authenticating by credentials you're not Authenticating by JWT so you will not have these additional properties populated on your User Session. If they're embedded in your JWT's body payload then as TimeZone is a AuthUserSession property, it should be populated if it was contained within the JWT payload:
case "TimeZone":
authSession.TimeZone = entry.Value;
break;
But DateFormat is not an AuthUserSession property so you will need to populate it manually by providing an implementation for PopulateSessionFilter, e.g:
new JwtAuthProvider(AppSettings)
{
PopulateSessionFilter = (session,payload,req) =>
session.Meta["DateFormat"] = payload["DateFormat"];
}
But these properties are only going populated in the Users Session when authenticating via JWT.
To help diagnose any issues you should but a breakpoint in your CreatePayloadFilter to see what you've populated the JWT payload with and conversely put a breakpoint in your PopulateSessionFilter to inspect what's contained in the payload and resulting populated session.

how to save entire conversation from bot into stoarge?

I have made a bot in v4 framework using c#. I want to save the entire conversation into a storage , in a readable format . Our requirement is to save the bot conversation in a readable format or plain text. In my case only user info is getting saved not the conversation between user and the bot.
You can use a middleware for that: TranscriptLoggerMiddleware
More info on middlewares
The middleware will handle saving transcript for you in a storage.
you can use below code
I have worked on nodejs but it should be similar to C#.
For each step call the logActivity
const { preserveService } = require('../../../Service/dbService');
await preserveService.logActivity(step.context, userData,Any param);
logActivity : async function (turnContext, userData,Any param){
try{
let userInfo = await userDataUtil.getUserInfo(turnContext,userData);
colNameAndValueArray = [
{
[PROPERTY_NAME.COLUMN_NAME] : 'response_from',
[PROPERTY_NAME.VALUE] : responsefrom,
[PROPERTY_NAME.DATATYPE] : DATATYPE.STRING
},
{
[PROPERTY_NAME.COLUMN_NAME] : 'user_session_id',
[PROPERTY_NAME.VALUE] : userInfo.userId,
[PROPERTY_NAME.DATATYPE] : DATATYPE.STRING
},
{
//conversation_id
[PROPERTY_NAME.COLUMN_NAME] : 'conversation_id',
[PROPERTY_NAME.VALUE] : turnContext._activity.conversation.id,
[PROPERTY_NAME.DATATYPE] : DATATYPE.STRING
},
{
[PROPERTY_NAME.COLUMN_NAME] : 'is_answered',
[PROPERTY_NAME.VALUE] : isAnswered,
[PROPERTY_NAME.DATATYPE] : DATATYPE.BOOLEAN
}
]
await this.insert(CONFIG.DB.AUDIT_TABLE, colNameAndValueArray);
}catch(err){
console.log(`------------------------`);
console.log(`Error occurred while inserting audit logs`);
console.log(err);
console.log(`------------------------`);
}}
insert : async function(tableName, colNameAndValueArray, returnColumnName){
let query = null;
try{
if(util.isNotEmptyString(tableName) && util.isNotEmptyArray(colNameAndValueArray)){
let columnNames = dbUtil.getColNames(colNameAndValueArray);
let columnValues = dbUtil.getColValues(colNameAndValueArray);
if(columnNames == null || columnValues == null){
throw new Error('Invalid column name or value. Kindly check the value you have passed');
}
query = `INSERT INTO ${tableName} (${columnNames}) VALUES (${columnValues}) ${util.isNotEmptyString(returnColumnName)? ` RETURNING ${returnColumnName}`: ''}`;
console.log(`------------------------`);
console.log(`Query : ${query}`);
console.log(`------------------------`);
return this.executeQuery(query);
}else{
return Promise.reject(REQUIRED_PARAMETER_MISSING);
}
}catch(err){
console.log(`------------------------`);
console.log(`Error occurred while executing insert query : ${ query != null ? query : '' }`);
console.log(err);
console.log(`------------------------`);
return Promise.reject(err);
}}
Hope this helps
Sanjeev Guatam

Date and datetime set to null in beforeValidate transforms to '0000-00-00' and throws error

I've looked quite extensively around for an answer to how to handle my date-related problem, but I can't seem to find a proper answer anywhere.
I'm using SailsJS (beta) with Waterline as the data-handler. My case is as follows:
My User-model is as such:
module.exports = {
attributes: {
(.. some attributes ..),
birthDate: {
type: 'date',
required: false
}
},
// Modifies user input before validation
beforeValidation: function(user, cb){
// Make sure birthdate is not saved as 0000-00-00
if(!user.birthDate || user.birthDate == '0000-00-00'){
user.birthDate == null;
}
cb(null, user);
},
}
The beforeValidation()-function triggers as it should, but I always gets thrown an error as follows. This seems to be the case for both date and datetime types in Waterline models.
warn: Error (E_VALIDATION) :: 1 attribute is invalid
at WLValidationError.WLError (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\error\WLError.js:33:18)
at new WLValidationError (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\error\WLValidationError.js:20:28)
at C:\web\node_modules\sails\node_modules\waterline\lib\waterline\query\validate.js:44:43
at allValidationsChecked (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:181:5)
at done (C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:128:19)
at C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:25:16
at C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:162:23
at Object.async.each (C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:114:20)
at validate (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:142:11)
at C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:118:13
Invalid attributes sent to User:
birthDate
`undefined` should be a date (instead of "0000-00-00", which is a string)
How do I set the birthDate to null in the database using sailsjs/waterline?
I hope someone can help:)
change
cb(null, user);
to
cb();
And you have a type-mistake in the if-statement:
user.birthDate == null;
have to be
user.birthDate = null;

Invalid Resource Id when batch inserting

I am doing a batch insert into the Google Calendar using the .NET API. I have the following code.
var request = new BatchRequest(calendarService);
request.Queue<Event>(
calendarService.Events.Insert(
new Event
{
Id = String.Format("yot-{0}", item.AppointmentId),
Summary = item.Title,
Description = item.Description,
Start = new EventDateTime() { DateTime = item.Date },
End = new EventDateTime() { DateTime = item.Date.AddHours(item.Length) }
}, calendar.Id),
(content, error, i, message) =>
{
//Log error
});
request.ExecuteAsync();
When I execute and try and insert I get the error "Invalid resource id". What does this error mean?
You have to follow the guidelines defined here : https://developers.google.com/google-apps/calendar/v3/reference/events/insert
Basically, the id has to be between 5 and 1024 characters long and consist solely from characters in this alphabet : 0123456789abcdefghijklmnopqrstuv.
Try with a simple Guid.NewGuid() or use a Base32 Encoder if you don't want random IDs

Resources