I have an app that syncronizes with QuickBooks using qbXml and the Intuit Web Connector.
I've noticed some unusual behavior when querying accounts. According to the spec, an account's FullName should include the names of any of its ancestors, separated by colons. Like "grandparent:parent:account".
In this one particular case, however, I'm getting a return from AccountQuery where the account clearly has a parent but the FullName does not reflect the parent's name. This only happens for one particular user, QB 2012 Pro.
Is there a setting or circumstance that causes QB to shift gears and not include the parent name in the FullName of an account?
Here's an example of an account with a fishy FullName (some info changed for privacy).
<AccountRet>
<ListID>800000BD-1328833123</ListID>
<TimeCreated>2012-02-09T18:20:40-06:00</TimeCreated>
<TimeModified>2013-02-18T10:49:29-06:00</TimeModified>
<EditSequence>1361206169</EditSequence>
<Name>My Account</Name>
<FullName>My Account</FullName>
<IsActive>true</IsActive>
<ParentRef>
<ListID>80000037-1324501345</ListID>
<FullName>Parent Account</FullName>
</ParentRef>
<Sublevel>1</Sublevel>
<AccountType>Income</AccountType>
<AccountNumber>5025.2</AccountNumber>
<Balance>9.99</Balance>
<TotalBalance>9.99</TotalBalance>
<CashFlowClassification>None</CashFlowClassification>
</AccountRet>
This situation is caused by the user having the following Preference turned on in QuickBooks:
Edit > Preferences > Accounting > Company Preferences > Show lowest subaccount only
So you have two choices:
(1) Get the user to turn off that preference, or
(2) Use the ParentRef data to link each AccountRet to its parent Account.
Thanks to Karl Irvin for a heads-up which helped me solve this.
Related
I wrote a program that downloads orders from a website and creates invoices using the SDK.
A few products are listed as Groups in QuickBooks, so when adding them to the invoice, I can't list the price.
If IList.Item(x).Type = 2 Then
Dim ORInvoiceLineAddListElement2 As IORInvoiceLineAdd
ORInvoiceLineAddListElement2 = newInvoice.ORInvoiceLineAddList.Append()
ORInvoiceLineAddListElement2.InvoiceLineGroupAdd.ItemGroupRef.FullName.SetValue(IList.Item(x).FullName)
ORInvoiceLineAddListElement2.InvoiceLineGroupAdd.Quantity.SetValue(IList.Item(x).Quantity)
'ORInvoiceLineAddListElement2.InvoiceLineGroupAdd.Desc.SetValue(IList.Item(x).DESC)
End If
This will input into QuickBooks just fine, however, the price will be based on a retail customer, even if the customer class is set to wholesale. I know that the customer class is correct because everything else shows up correctly in the generated invoice.
Any suggestions on what i could try to get this group item priced correctly?
Thanks for your help!!!
QuickBooks Class codes have nothing at all to do with pricing. They have no effect what-so-ever on pricing in any form or manner.
What makes you think setting the Class should change pricing in any way?
I was having the same issue. what is happening is the Group line items are being assigned the Default Price from the Items table. shouldn't have anything to do with the Class. I did find the following support answer which seems to apply to both Desktop and Online versions of QuickBooks:
"The SDK does not currently support adjusting the price of group items when adding an invoice, even though the default UI in QuickBooks allows this. You can modify an invoice and change the line item amounts, so you would need to first call create the add, read the response to get the transaction id and edit sequence, then do an Invoice Mod request on the invoice to set the rates that you want."
Intuit Developer Page
We ran the Fortify scan and had some Access Control: Database issues. The code is getting the textbox value and setting it to a string variable. In this case, it's passing the value from the TextBox to the stored procedure in a database. Any ideas on how I can get around this Access Control: Database issue?
Without proper access control, the method ExecuteNonQuery() in DataBase.cs
can execute a SQL statement on line 320 that contains an attacker-controlled primary
key, thereby allowing the attacker to access unauthorized records.
Source: Tool.ascx.cs:591 System.Web.UI.WebControls.TextBox.get_Text()
rptItem.FindControl("lblClmInvalidEntry").Visible = false;
ToolDataAccess.UpdateToolData(strSDN, strSSNum, strRANC, strAdvRecDate, strAdvSubDate, strClmRecDate, strClmAuth, strClmSubDate, strAdvAuth, txtNoteEntry.Text);
Sink: DataBase.cs:278
System.Data.SqlClient.SqlParameterCollection.Add()
// Add parameters
foreach (SqlParameter parameter in parameters)
cmd.Parameters.Add(parameter);
The point of "Access Control: Database" is where it isn't being specific enough in the query and so could potentially allow a user to see information that they're not supposed to.
An easy example of this vulnerability would be a payroll database where there is a textbox that says the ID of the employee and gives their salary, this could potentially allow the user to change the ID and see the salary of other employees.
Another example where this is often intended functionality is in a website URL where the product ID is used in a parameter, meaning a user could go through every product you have on your site. But as this only allows users to see information they're supposed to be able to, it's not particularly a security issue.
For instance:
"SELECT account_balance FROM accounts WHERE account_number = " + $input_from_attacker + ";"
// even if we safely build the query above, preventing change to the query structure,
// the attacker can still send someone else's account number, and read Grandma's balance!
As this is pretty context based, it's difficult to determine statically so there are lots of examples where Fortify may catch this but it's actually intended functionality. That's not to say the tool is broken, it's just one of the limitations of static analysis and depending on what your program is supposed to be doing it may or may not be intended.
If this is intended to work like this, then I would suggest auditing it as not an issue or suppressing the issue.
If you can see that this is definitely an issue and users can see information that they shouldn't be able to, then the stored procedure needs to be more specific so that users can only see information they should be able to. However SCA will likely still pick this up in a latter scan so you would still then need to audit it as fixed and no longer an issue.
When I query for customers I get back a customer object with all the info. one of the properties is the Address. this contains the billing and shipping addresses for the customer. however, the id field for each address is always null. I am wondering how I push an update back to QBO without the id? how does QBO know which address I am changing without a key of some kind? my goal is to be able to query QBO and get all the customers and address that have changed since a specified date. I have all this working for the customer but need to do the same for addresses. I am going by the assumption that when an address is changed in QBO that is sets the modified timestamp for that customer record. can anyone tell me how I manage the addresses for a customer and be able to push updates back to QBO?
Try using tag(Billing/Shipping) attribute while updating the address. I've tested the same and it is working fine.
You mentioned earlier that you were getting the id field of address as null. It is becuase, the devkit works with both - QBO and QBD. QBD returns valid element id but QBO doesn't. So for QBO, Devkit shows null in place of element id(in your case - address's id).
You can test all these using api explorer(http://developer.intuit.com/apiexplorer).
Hope it will solve your porb.
Thanks
'the id field for each address is always null' - this line is not very clear to me. Did you mean the id of the customer entity ? Plz explain.
You can check the QBO-Customer object's documentation and sample update request xml, from the following Link - https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services/0400_QuickBooks_Online/Customer .
For testing you can use the api-explorer. Link - developer.intuit.com/apiexplorer
Thanks
Manas
In my Team Foundation Server, I have a collection containing a Team Project. This Team Project has several contributors. The following lines of code get all contributors of that project:
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri("http://tfs:8080/tfs/CollectionName"));
IGroupSecurityService groupSecurityService = collection.GetService<IGroupSecurityService>();
Identity contributors = groupSecurityService.ReadIdentity(SearchFactor.AccountName, "[ProjectName]\\Contributors", QueryMembership.Expanded);
Identity[] members = groupSecurityService.ReadIdentities(SearchFactor.Sid, contributors.Members, QueryMembership.None);
Each Identity in members has a Property MailAddress, which in my case is equal to string.Empty.
Where do I administrate those mail addresses?
My first idea was to have a look at the users in Start->Administrative Tools->Computer Management->Users
I selected one of the users and opened his properties. I thought there might be an email property that the TFS would take. But I couldn't find one.
Then I opened the TFS Administration Console, looked for Group Membership and navigated to one of the users. There is also no way of editing properties.
Does anyone know where to set that email address?
Great question! There is a TFS job that is scheduled to run every hour to update information about security identities stored in TFS against the details in Active Directory. Some of this information includes the display name, security identifier (SID), AD distinguished name, and e-mail address, among other details. You can find out this cache of details by looking at the tbl_security_identity_cache table in the configuration database.
Warning: Querying against or changing the database puts you in a position where you will likely not be able to get support from Microsoft. It's advised that you don't do this unless instructed by a Microsoft support representative in the context of an active support case. You were actually doing it right by using the TFS SDK to get this information.
If your TFS environment is not in an Active Directory environment, then it will attempt to synchronize information from the local machine where TFS is running. It won't have details about the e-mail address to use so it will be left blank.
Starting in the next version of TFS after TFS 2010, each user will be able to update their notification e-mail address in their profile using Team Web Access.
The following is for TFS 2013 Update 5
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
What follows is not for the uninitiated. ** Proceed at your own risk. **
Locate the user or users with email addresses needing to be set. There can be duplicates in the Identities table. I found that the ones with the highest SequenceId were the active Identities.
Use Tfs_TFSConfiguration
SELECT i1.AccountName, i1.Id FROM tbl_Identity AS i1
LEFT OUTER JOIN tbl_Identity AS i2
ON (i1.AccountName=i2.AccountName AND i1.SequenceId<i2.SequenceId)
WHERE i2.AccountName IS NULL
AND i1.AccountName in ('<your first user>','<another user>','<and so on>')
This gives a list of the most recent the Id(s), in GUID form, for the accounts that you need to update. These GUIDs must be reformatted into ArtifactId(s), which is a transformed binary format. This is accomplished by reversing the byte order (low to high) or each of the first three parts of the GUID, but leaving the last two parts in order. E.g.:
Returned 'Id' GUID =01020304-0506-0708-090A-0B0C0D0E0F10
Byte Swapped GUID =04030201-0605-0807-090A-0B0C0D0E0F10
Reformatted 'ArtifacId'=0x0403020106050807090A0B0C0D0E0F10
Next, you have to find the PropertyId(s) used by TFS for email notifications. In TFS 2013 U5, this can be found with the following query:
USE Tfs_TFSConfiguration
SELECT Name, PropertyId FROM tbl_PropertyDefinition WHERE Name LIKE '%Address%'
This will give you the PropertyId(s) for ConfirmedNotificationAddress and CustomNotificationAddresses; which are the two property fields used by TFS 2013 U5 to send notification emails.
Next, you have to find the InternalKindId for the Identity Framework for the TFS DatabaseCategory
USE Tfs_TFSConfiguration
SELECT Description, InternalKindId FROM tbl_PropertyArtifactKind
WHERE Description='Identity'
Now to put it all together, ...
If the configuration records for your user(s) already exist, you can update the settings with:
USE Tfs_TFSConfiguration
UPDATE tbl_PropertyValue SET LeadingStringValue='<user's notification email address>'
WHERE ArtifactId=<ArtifactId, reformatted from tbl_Identity query>
AND PropertyId IN ('<first PropertyId from tbl_PropertyDefinition>', '<second id>')
Note: that ArtifactId is a binary value, based upon a semi-byte-swapped database GUID, and will not match a quoted value in the UPDATE query. I.e. this part of the query will look something like:
WHERE ArtifactId=0x90D490F6BF7B31491CB894323F38A91F AND
Below I assume that the PartitionId is '1'; this should be verified before you continue by a brief scan of the records in the tbl_PropertyValue table.
If you are loading configuration settings that have not yet been set:
USE Tfs_TFSConfiguration
INSERT INTO tbl_PropertyValue
(PartitionId, ArtifactId, InternalKindId, Version, PropertyId, LeadingStringValue)
VALUES ('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<first PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>'),
('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<second PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>')
Note: that ArtifactId must be an unquoted binary value, transformed from the GUID returned from the tbl_Identity as explained above.
Note: that two records are created for each ArtifactId, one for each PropertyId.
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
** Proceed at your own risk. **
(This works for me, ... but, I do not have a Microsoft Support Agreement to invalidate.)
If Active Directory does not get synched with TFS, and assuming your goal to keep email address is for sending notifications you can use the IEventService.GetEventSubscriptions() methods.
var eventService = (IEventService)collection.GetService(typeof(IEventService));
foreach (var member in members)
{
var subscription = eventService.GetEventSubscriptions(member.DisplayName).First();
{
if (subscription != null && string.IsNullOrEmpty(member.MailAddress))
member.MailAddress = subscription.DeliveryPreference.Address;
}
}
I believe this is kept in Active Directory.
For TFS2017+, each user can have a preferred email address, that they can setup in their profile, on the web interface.
It can override, or replace the email set in Active Directory. It also has the benefit to be an instant change, no synchronisation needed.
The field will be initialized with the value that has been set in Active Directory. The synchronization doesn't seem to happen anymore.
In my Team Foundation Server, I have a collection containing a Team Project. This Team Project has several contributors. The following lines of code get all contributors of that project:
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri("http://tfs:8080/tfs/CollectionName"));
IGroupSecurityService groupSecurityService = collection.GetService<IGroupSecurityService>();
Identity contributors = groupSecurityService.ReadIdentity(SearchFactor.AccountName, "[ProjectName]\\Contributors", QueryMembership.Expanded);
Identity[] members = groupSecurityService.ReadIdentities(SearchFactor.Sid, contributors.Members, QueryMembership.None);
Each Identity in members has a Property MailAddress, which in my case is equal to string.Empty.
Where do I administrate those mail addresses?
My first idea was to have a look at the users in Start->Administrative Tools->Computer Management->Users
I selected one of the users and opened his properties. I thought there might be an email property that the TFS would take. But I couldn't find one.
Then I opened the TFS Administration Console, looked for Group Membership and navigated to one of the users. There is also no way of editing properties.
Does anyone know where to set that email address?
Great question! There is a TFS job that is scheduled to run every hour to update information about security identities stored in TFS against the details in Active Directory. Some of this information includes the display name, security identifier (SID), AD distinguished name, and e-mail address, among other details. You can find out this cache of details by looking at the tbl_security_identity_cache table in the configuration database.
Warning: Querying against or changing the database puts you in a position where you will likely not be able to get support from Microsoft. It's advised that you don't do this unless instructed by a Microsoft support representative in the context of an active support case. You were actually doing it right by using the TFS SDK to get this information.
If your TFS environment is not in an Active Directory environment, then it will attempt to synchronize information from the local machine where TFS is running. It won't have details about the e-mail address to use so it will be left blank.
Starting in the next version of TFS after TFS 2010, each user will be able to update their notification e-mail address in their profile using Team Web Access.
The following is for TFS 2013 Update 5
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
What follows is not for the uninitiated. ** Proceed at your own risk. **
Locate the user or users with email addresses needing to be set. There can be duplicates in the Identities table. I found that the ones with the highest SequenceId were the active Identities.
Use Tfs_TFSConfiguration
SELECT i1.AccountName, i1.Id FROM tbl_Identity AS i1
LEFT OUTER JOIN tbl_Identity AS i2
ON (i1.AccountName=i2.AccountName AND i1.SequenceId<i2.SequenceId)
WHERE i2.AccountName IS NULL
AND i1.AccountName in ('<your first user>','<another user>','<and so on>')
This gives a list of the most recent the Id(s), in GUID form, for the accounts that you need to update. These GUIDs must be reformatted into ArtifactId(s), which is a transformed binary format. This is accomplished by reversing the byte order (low to high) or each of the first three parts of the GUID, but leaving the last two parts in order. E.g.:
Returned 'Id' GUID =01020304-0506-0708-090A-0B0C0D0E0F10
Byte Swapped GUID =04030201-0605-0807-090A-0B0C0D0E0F10
Reformatted 'ArtifacId'=0x0403020106050807090A0B0C0D0E0F10
Next, you have to find the PropertyId(s) used by TFS for email notifications. In TFS 2013 U5, this can be found with the following query:
USE Tfs_TFSConfiguration
SELECT Name, PropertyId FROM tbl_PropertyDefinition WHERE Name LIKE '%Address%'
This will give you the PropertyId(s) for ConfirmedNotificationAddress and CustomNotificationAddresses; which are the two property fields used by TFS 2013 U5 to send notification emails.
Next, you have to find the InternalKindId for the Identity Framework for the TFS DatabaseCategory
USE Tfs_TFSConfiguration
SELECT Description, InternalKindId FROM tbl_PropertyArtifactKind
WHERE Description='Identity'
Now to put it all together, ...
If the configuration records for your user(s) already exist, you can update the settings with:
USE Tfs_TFSConfiguration
UPDATE tbl_PropertyValue SET LeadingStringValue='<user's notification email address>'
WHERE ArtifactId=<ArtifactId, reformatted from tbl_Identity query>
AND PropertyId IN ('<first PropertyId from tbl_PropertyDefinition>', '<second id>')
Note: that ArtifactId is a binary value, based upon a semi-byte-swapped database GUID, and will not match a quoted value in the UPDATE query. I.e. this part of the query will look something like:
WHERE ArtifactId=0x90D490F6BF7B31491CB894323F38A91F AND
Below I assume that the PartitionId is '1'; this should be verified before you continue by a brief scan of the records in the tbl_PropertyValue table.
If you are loading configuration settings that have not yet been set:
USE Tfs_TFSConfiguration
INSERT INTO tbl_PropertyValue
(PartitionId, ArtifactId, InternalKindId, Version, PropertyId, LeadingStringValue)
VALUES ('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<first PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>'),
('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<second PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>')
Note: that ArtifactId must be an unquoted binary value, transformed from the GUID returned from the tbl_Identity as explained above.
Note: that two records are created for each ArtifactId, one for each PropertyId.
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
** Proceed at your own risk. **
(This works for me, ... but, I do not have a Microsoft Support Agreement to invalidate.)
If Active Directory does not get synched with TFS, and assuming your goal to keep email address is for sending notifications you can use the IEventService.GetEventSubscriptions() methods.
var eventService = (IEventService)collection.GetService(typeof(IEventService));
foreach (var member in members)
{
var subscription = eventService.GetEventSubscriptions(member.DisplayName).First();
{
if (subscription != null && string.IsNullOrEmpty(member.MailAddress))
member.MailAddress = subscription.DeliveryPreference.Address;
}
}
I believe this is kept in Active Directory.
For TFS2017+, each user can have a preferred email address, that they can setup in their profile, on the web interface.
It can override, or replace the email set in Active Directory. It also has the benefit to be an instant change, no synchronisation needed.
The field will be initialized with the value that has been set in Active Directory. The synchronization doesn't seem to happen anymore.