Setting the orderLine property on an item when updating an invoice - c#

My problem is that after creating an invoice, I can never get new line items to reference their corresponding sales order line item.
I have been generating invoices via SuiteTalk. When I initially create an invoice, I empty the lineItemList and add back in the items I need. I make sure the orderLine property matches the sales order line item line number. This works great.
But when I try and update the invoice with additional line items, I can never get the new items to retain their orderLine property. The orderLine property is used for the "Invoiced" column on the Sales Order.
In order to get the referencing to be correct, I need to delete the invoice and create it again with all of the line items I need.
Does anyone know if what I am trying to do is possible?
In this example, I use this CreateInvoice function to create the invoice from scratch and add it to NetSuite. Everything works as expected.
public void CreateInvoice(SalesOrder salesOrder) {
Invoice brandNewInvoice = new Invoice() {
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
entity = salesOrder.entity,
tranDate = endDate,
tranDateSpecified = true,
startDate = startDate,
startDateSpecified = true,
endDate = endDate,
endDateSpecified = true,
itemList = new InvoiceItemList(),
};
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.add(brandNewInvoice);
}
In this example, the invoice is already created and so I get it from NetSuite and then replace the existing itemList with a new one. After the update, the invoice will now have NO orderLine property for any of the line items. The invoice also loses its "Created From" field because there are no line items with the orderLine property set.
public void UpdateInvoice(SalesOrder salesOrder, String invoiceInternalId) {
Invoice invoice = GetNetSuiteInvoice(invoiceInternalId);
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.update(invoice);
}
this is the function used to create the itemList:
public InvoiceItem[] GetInvoiceItemList(SalesOrder salesOrder) {
InvoiceItem[] invoiceItemList = new InvoiceItem[salesOrder.itemList.item.Length];
for (int i = 0; i < salesOrder.itemList.item.Length; i++) {
SalesOrderItem soItem = salesOrder.itemList.item[i];
double quantity = 1;
invoiceItemList[i] = new InvoiceItem() {
item = new RecordRef() {
internalId = soItem.item.internalId,
name = soItem.item.name,
},
amount = quantity * Double.Parse(soItem.rate),
amountSpecified = true,
quantity = quantity,
quantitySpecified = true,
price = new RecordRef() {
internalId = soItem.price.internalId,
name = soItem.price.name,
},
rate = soItem.rate,
orderLine = soItem.line, //this will establish the link between the invoice and the sales order
orderLineSpecified = true,
taxRate1 = soItem.taxRate1,
taxRate1Specified = true,
};
}
return invoiceItemList;
}

Actually what you are looking for is the intialize operation. You need to use initialize in order for Netsuite to properly fill in the created from and orderline props. From the NS Help there is a C# example of creating a Cash Sale:
private void Initialize()
{
this.login(true);
InitializeRef ref1 = new InitializeRef();
ref1.type = InitializeRefType.salesOrder;
//internal id of the sales order to be converted to cash sale
ref1.internalId = "792";
ref1.typeSpecified = true;
InitializeRecord rec = new InitializeRecord();
rec.type = InitializeType.cashSale;
rec.reference = ref1;
ReadResponse read1 = _service.initialize(rec);
}

This is normal, when transforming a transaction to another transaction (e.g. SO to Inv, PO to IR). When you transform, most of the information from the source transaction will be carried over. Like what you are doing which is creating an Invoice from Sales Order(Base on your code below).
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
You don't need to get the line item information from the Sales Order and put it in the Invoice because it will be pre-populated once you create it form Sales Oder(unless you need to change a value of a line item column).
One behavior of a transformed record(Invoice in your case), if you remove a line item from the Invoice you will lose the link to the Sales order(orderLine) and if you remove all the line item you will totally lose the link between the two transactions (createdfrom). This is what you are experiencing. orderLine/createdFrom is a field populated by the system, it looks like you are populating it but you are not.

Related

How to set multiple values of properties inside an object in C#?

Please tell me how to add multiple properties inside an single object.
like- if there is a class having 5 variables defined with get and set.
I want to add like 2 values for each variable through a single object of that class like
class Info{
int count{get , set,};
string name{get , set,};
string Dept {get , set,};
string Address {get , set,};
long contact {get , set,};
info obj =new Info();
/* Now after this I want to take 2 rows like
in first row I want to set it's values through a single object
Count=1,name="Robert",Dept="Computer",Address="India",Contact=434343
in row 2nd row
Count=1,name="Robbin",Dept="Electronic",Address="Colombo",Contact=54545
*/
}
/// Now please explain me how to set like above two rows values inside one object.. ///
I think what you're looking for is inline object initialization: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer
You can write it on a single line but the code would look better if you break it into multiple lines:
Info infoObj = new Info
{
Count = 1,
Name = "Robert",
Dept = "Computer",
Address = "India",
Contact = 434343
};
If what you mean is initializing a class with set properties, look at Peter Sandor's answer.
if you're looking to declare a class with a set of fields that'll be filled with values upon initialization without giving them values (aka. default values), then this might help:
class Info
{
public int count = 5;
pubic string name = "Robert"
}
Please note that these are fields and not properties though, if you'd like to do the same with properties instead of fields, i'd suggest doing this with propfull:
private int count = 5;
public int Count
{
get { return count; }
set { count = value; }
}
Hope this helps!
Instead of creating an instance of the Info class, make a List of Info:
List<Info> aSingleObj = new List<Info>();
Now you can add as many things to the single object:
aSingleObj.add(new Info { Count = 1, name = "Robert", Dept = "Computer", Address = "India", contact = "434343" });
aSingleObj.add(new Info { Count = 1, name = "Robbin", Dept = "Electronic", Address = "Colombo", contact = "54545" });
To distinguish between them, and print the output, do:
Console.WriteLine($"First row: Count = {aSingleObj[0].Count}, Name = {aSingleObj[0].name}, Department: {aSingleObj[0].Dept}, Address = {aSingleObj[0].Address}, Contact = {aSingleObj[0].contact}");
and for second row:
Console.WriteLine($"Second row: Count = {aSingleObj[1].Count}, Name = {aSingleObj[1].name}, Department: {aSingleObj[1].Dept}, Address = {aSingleObj[1].Address}, Contact = {aSingleObj[1].contact}");

Loop through Request.Forms to get Field Values for Bulk Update

I have a list of records generated from a search query in my View. There's certain fields that can be edited and next step is do update those fields with one button/action.
The yellow fields are the ones that have been edited, while the white fields still match what is in the database table. Now when I click update all I first get the values of sellprice and casecost from the DB, then I get the values from the form. If the values match then move on, if the values from the form have been changed then update. I have datareader that reads the values from the table/database perfectly fine for each line of records on page.
NpgsqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
var prod = new ProductViewModel();
prod.q_guid = Guid.Parse(dr["q_guid"].ToString());
prod.q_sellprice = Convert.ToDecimal(dr["q_sellprice"]);
prod.q_casecost = Convert.ToDecimal(dr["q_casecost"]);
/*
At this point
Need to compare dr.Read q_sellprice and q_casecost
with changed values in the fields
if != then update for that record
*/
/*Lets assign previous values (values in db) to variables*/
var previousSellprice = prod.q_sellprice;
var previousCasecost = prod.q_casecost;
var thatId = prod.q_guid;
/*Lets get current values from form/list*/
var priceList = Request.Form["item.q_sellprice"];
var costList = Request.Form["item.q_casecost"];
/*eg*/
if (previousSellprice != currentSellprice || previousCasecost != currentCasecost)
{
//lets update record with new values from view
}
-> loop move on to next row in view
My DataReader while loop can get the value of each row no problemo. What I am trying to achieve when it gets the values of the first row from the db, then
I need to check what the current values in the form for that record are
if they are different then update for that current row
move on to next row in the view/on page
I have managed to get the array of values for these fields with these variables with the following code. This has the edited/changed fields from the list/form.
var priceList = Request.Form["item.q_sellprice"];
var costList = Request.Form["item.q_casecost"];
On my first run through the loop, I would like to get the values 10.00 and 8.50, do my check, update if necessary.. then move on the next row which will get 3.33 and 8.88, do my check, and update if necessary and so on for the rest of the records on that page.
So how can I loop through Request.Forms in the instance, and get my individual values for one record at a time?
cshtml on view for the fields is
#foreach (var item in Model)
{
<td>
€ #Html.EditorFor(modelItem => item.q_sellprice, new { name="q_sellprice" })
</td>
<td>
€ #Html.EditorFor(modelItem => item.q_casecost, new { name="q_casecost"})
</td>
Addition: Updating isnt the issue, getting the values of each record from the array while looping through the form fields is.
It is a long description of the problem - but from my understanding, your only problem is, that you want to have some data, which right now is two strings to be as List of operations (data) to perform? Is that correct?
If so - you can have such data in List using Zip method:
void Main()
{
string priceList = "1,2,3,4";
string costList = "2,3,4,5";
var prices = priceList.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries);
var costs = costList.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries);
var collectionToUpdate = prices.Zip(costs, (price, cost) => new PriceToUpdate(price, cost));
//do update in database with collectionToUpdate
}
public class PriceToUpdate
{
public PriceToUpdate(string oldPrice, string newPrice)
{
decimal priceTmp;
if (decimal.TryParse(oldPrice, out priceTmp))
{
OldPrice = priceTmp;
}
if (decimal.TryParse(newPrice, out priceTmp))
{
NewPrice = priceTmp;
}
}
public decimal OldPrice { get; set; }
public decimal NewPrice { get; set; }
}
My suggestion would be to re-organise your HTML a bit more and modify the method for getting the fields parsed out. What I have done in the past is include the Key Id (in your case the Guid) as part of the output. So the result in a basic view looks like:
If you notice the name attribute (and Id) are prefixed with the q_guid field. Here is my basic model.
public class ProductViewModelItems
{
public IList<ProductViewModel> items { get; set; } = new List<ProductViewModel>();
}
public class ProductViewModel
{
public Guid q_guid { get; set; }
public decimal q_sellprice { get; set; }
public decimal q_casecost { get; set; }
//other properties
}
And my controller just has a simple static model. Of course yours is built from your database.
static ProductViewModelItems viewModel = new ProductViewModelItems()
{
items = new[]
{
new ProductViewModel { q_casecost = 8.50M, q_sellprice = 10M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 8.88M, q_sellprice = 3.33M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 9.60M, q_sellprice = 3.00M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 9.00M, q_sellprice = 5.00M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 10M, q_sellprice = 2.99M, q_guid = Guid.NewGuid() },
}
};
[HttpGet]
public ActionResult Index()
{
//load your view model from database (note mine is just static)
return View(viewModel);
}
Now we construct our form so that we can pull it back in our post method. So I have chosen the format of {q_guid}_{field_name} as
q_casecost = {q_guid}_q_casecost
q_sellprice = {q_guid}_q_sellprice
The form construction now looks like.
#foreach (var item in Model.items)
{
<tr>
<td>
€ #Html.TextBoxFor(modelItem => item.q_sellprice, new { Name = string.Format("{0}_q_sellprice", item.q_guid), id = string.Format("{0}_q_sellprice", item.q_guid) })
</td>
<td>
€ #Html.TextBoxFor(modelItem => item.q_casecost, new { Name = string.Format("{0}_q_casecost", item.q_guid), id = string.Format("{0}_q_casecost", item.q_guid) })
</td>
</tr>
}
Note there a few key items here. First off you cant modify the Name attribute using EditorFor() so I have swapped this out to a TextBoxFor() method.
Next I am overriding the Name attribute (note it must be Name not name [lower case ignored]).
Finally the POST action runs much differently.
[HttpPost]
public ActionResult Index(FormCollection form)
{
IList<ProductViewModel> updateItems = new List<ProductViewModel>();
// form key formats
// q_casecost = {q_guid}_q_casecost
// q_sellprice = {q_guid}_q_sellprice
//load your view model from database (note mine is just static)
foreach(var item in viewModel.items)
{
var caseCostStr = form.Get(string.Format("{0}_q_casecost", item.q_guid)) ?? "";
var sellPriceStr = form.Get(string.Format("{0}_q_sellprice", item.q_guid)) ?? "";
decimal caseCost = decimal.Zero,
sellPrice = decimal.Zero;
bool hasChanges = false;
if (decimal.TryParse(caseCostStr, out caseCost) && caseCost != item.q_casecost)
{
item.q_casecost = caseCost;
hasChanges = true;
}
if(decimal.TryParse(sellPriceStr, out sellPrice) && sellPrice != item.q_sellprice)
{
item.q_sellprice = sellPrice;
hasChanges = true;
}
if (hasChanges)
updateItems.Add(item);
}
//now updateItems contains only the items that have changes.
return View();
}
So there is alot going on in here but if we break it down its quite simple. First off the Action is accepting a FormCollection object which is the raw form as a NameValuePairCollection which will contain all the keys\values of the form.
public ActionResult Index(FormCollection form)
The next step is to load your view model from your database as you have done before. The order you are loading is not important as we will interate it again. (Note i am just using the static one as before).
Then we iterate over each item in the viewmodel you loaded and now are parsing the form values out of the FormCollection.
var caseCostStr = form.Get(string.Format("{0}_q_casecost", item.q_guid)) ?? "";
var sellPriceStr = form.Get(string.Format("{0}_q_sellprice", item.q_guid)) ?? "";
This will capture the value from the form based on the q_guid again looking back at the formats we used before.
Next you parse the string values to a decimal and compare them to the original values. If either value (q_sellprice or q_casecost) are different we flag as changed and add them to the updateItems collection.
Finally our updateItems variable now contains all the elements that have a change and you can commit those back to your database.
I hope this helps.

TransactionSearch with body field condition Suitetalk

This is my case, I want to pull the Vendor Credit that have ApplyList.apply.doc (this is Vendor Bill ID) in a List of Vendor Bill ID.
I have to create a TransactionSearch, but I don't know how to apply a condition for this.
For now, I just know to create a search with Status, Type, but that's not enough.
Here is my code :
var transactionsSearch = new TransactionSearch
{
basic = new TransactionSearchBasic
{
//we only want credits with an "Open" status
billingStatus = new SearchBooleanField
{
searchValue = isOpen,
searchValueSpecified = true
},
//only search for those with a type of "_vendorCredit"
type = new SearchEnumMultiSelectField
{
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] { "_vendorCredit" }
},
}
};
I figured out the answer.
I have to use property Applied To Transaction in TransactionSearchBasic, that will be an array of Record Ref.

Creating product/Service in Quickbooks Online in an Invoice line item

I'm trying to create the service/product type in the invoice line item. It returns an error saying bad request, is my ItemRef phrased correctly. My service/product is created in qbo already, its called Subscription Fee, it's the 3rd in the dropdown list.
line.AnyIntuitObject = new Intuit.Ipp.Data.SalesItemLineDetail()
{
ItemRef = new Intuit.Ipp.Data.ReferenceType()
{
Value = "3",
type = "Item",
name = "Subscription Fee"
},
ItemElementName = Intuit.Ipp.Data.ItemChoiceType.UnitPrice,
AnyIntuitObject = (decimal)item.Rate, // Line item rate
Qty = (decimal)item.Quantity,
QtySpecified = true,
ServiceDate = DateTime.Now.Date,
ServiceDateSpecified = true,
TaxCodeRef = new Intuit.Ipp.Data.ReferenceType()
{
Value = taxCode0ZR.Id,
type = Enum.GetName(typeof(Intuit.Ipp.Data.objectNameEnumType), Intuit.Ipp.Data.objectNameEnumType.TaxRate),
name = taxCode0ZR.Name
},
};
What am i creating wrongly please help.
You cannot create an Item within an invoice or rather any entity within an entity.
QBO v3 does not supports creating entities on the fly.
You first need to do a create Item.
Get the Id of that Item and refer it in your Invoice.
Also, enable request/response log to get the details of the errors in log files-
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/0150_ipp_.net_devkit_3.0/0002_configuration/override_configuration

Unable to produce a chart using linq in csharp

I am coding in Microsoft Visual Studio 12 in ASP.net using c# and a noob at it.
This is what csv file looks like
ID, Engine Type, Car
111,vtec, 1
131,vtec, 1
157,boxer,1
148,boxer,1
167,vtec,1
158,,0
107,,0
ID should be a generic autonumber, Engine Type should be a type string and I don't know what Car should because it consists off 1's and 0's representing Boolean. This means that 1-customer has a car and 0 means that customer doesn't have a car.
This is how i create a list out of it.
var testingobject = (
from line in File.ReadAllLines("testing.csv").Skip(0)
let parts = line.Split(',')
select new
{
ID = parts[0],
Engine_Type = parts[1],
Car = parts[2] //should i put int32.parse(parts[2]) here
).ToList();
I create a simple array which consists of ID,Engine Type,Car convert it to a list using ToList() and then bind it to a dropdownlist, using this code:
string[] testingddl = new string[] { "ID", "Engine Type", "Car" };
List<String> mytestinglist = testingddl.ToList();
var mytestin = from m in mytestinglist
select m;
DropDownList1.DataSource = mytestin.AsEnumerable();
DropDownList1.DataTextField = "";
DropDownList1.DataValueField = "";
DropDownList1.DataBind();
User selects Car and should give me the a chart that has engine type in x-axis and total on y-axis.
The Problem: The column consists of 1's and 0's meaning whether the customer has a car (1) or doesnt (0).
I would like to view how many users have different types of engines types and bind it to a, say a column chart. So the data should display on the x-axis, engine type and y-axis should have the total. according to the data, there are 3 vtecs and 2 boxers. So vtecs represent a column with 3 total and boxers with 2.
I use this linq query and the following chart binding code.
if (tempval == "Car")// this is the current selected dropdown list value
{
var myfavitems = testingobject.Where(a => a.Car == "1").ToList();
foreach (var t in myfavitems.GroupBy(a => a.Engine_Type))
{
Series Series1 = new Series();
Chart1.Series.Add(Series1);
Chart1.Series[1].Points.AddXY(t.Key.ToString(), t.Count().ToString()).ToString();
Chart1.DataSource = myfavitems.AsEnumerable();
Chart1.Series[1].XValueMember = "Group Equipment Type";
Chart1.Series[1].YValueMembers = "Software";
Chart1.DataBind();
// ...??
The error comes at the point where I am reading my columns from the csv files. The error says Format exception was unhandled by user code: Input string was not in a correct format
select new
{
ID = parts[0],
Engine_Type = parts[1],
Car = Int32.Parse(parts[2])
}
I dont know what is wrong with that statement. Could someone please help me out.
You will want to have a class like this:
public class CarClass {
public int Id { get; set; }
public string Engine { get; set; }
public int Car { get; set; }
}
And then do something like:
var car_collection =
from line in File.ReadAllLines("your_csv_name.csv").Skip(1)
let parts = line.Split(',')
select new CarClass()
{
Id = Int32.Parse(parts[0]),
Engine = parts[1],
Car = Int32.Parse(parts[2])
};
var listy = car_collection.ToList();
Otherwise, notice the '{ }' and the '( )' , because yours don't match:
var car_collection =
(from line in File.ReadAllLines("your_csv_name.csv").Skip(1)
let parts = line.Split(',')
select new CarClass()
{
Id = Int32.Parse(parts[0]),
Engine = parts[1],
Car = Int32.Parse(parts[2])
}).ToList();
That should solve your problem with the error
If your header row is in CSV file then
Car = Int32.Parse(parts[2])
is trying to parse "Car" to Int32.
Try reading file with:
File.ReadAllLines("testing.csv").Skip(1)
to skip header row.

Categories

Resources