In Acumatica (Build 2020.5.2.368) we have done extensive customisations on the Project Task (DAC: PMTask) which saves correctly when we hit the Save button. When we want to push over some of the changes to the Revenue Budget tab (DAC: PMRevenueBudget) - we use the following code:
// Task updated
protected void PMTask_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e)
{
var row = (PMTask)e.Row;
PMTaskExt TaskExt = row.GetExtension<PMTaskExt>();
// Check Qty
if (TaskExt.UsrQuantity == 0)
{
TaskExt.UsrQuantity = 1;
}
if (TaskExt.UsrCostPrice != 0 && TaskExt.UsrMarginPerc != 0)
{
// do custom calculations here -- I removed the part of the code as it was useless for the purpose of posting here.
// Set custom fields
// These fields all have values greater than 0 --> Double Checked this
TaskExt.UsrMarkupPerc = TaskExt.UsrCostPrice * TaskExt.UsrQuantity / 100;
TaskExt.UsrLineCost = TaskExt.UsrCostPrice * TaskExt.UsrQuantity;
TaskExt.UsrSellPrice = TaskExt.UsrUnitPrice * TaskExt.UsrQuantity;
TaskExt.UsrTotalRevenue = TaskExt.UsrSellPrice - TaskExt.UsrLineCost;
TaskExt.UsrCostPriceCalculation = Convert.ToDecimal(12.00);
TaskExt.UsrUnitPriceCalculation = Convert.ToDecimal(88.99);
}
else
{
// More calculations
}
int revAccountID = 0;
int costAccountID = 0;
foreach (PMAccountGroup pmag in AccountInfo.Select())
{
if (pmag.GroupCD.Trim().Equals("INCOME"))
{
revAccountID = (int)pmag.GroupID; // 898
}
if (pmag.GroupCD.Trim().Equals("EXPENSES"))
{
costAccountID = (int)pmag.GroupID;
}
}
// Find the Inventory Type
InventoryItem inventory = InvetoryInfo.Search<InventoryItem.inventoryID>(TaskExt.UsrInventoryID);
string invUOM = "";
if (inventory != null)
{
invUOM = inventory.BaseUnit;
}
// Task --> Revenue Budget
PMRevenueBudget revbudgetItem = Base.RevenueBudget.Search<PMRevenueBudget.projectTaskID>(thisTask.TaskID);
if (revbudgetItem != null)
{
revbudgetItem.AccountGroupID = revAccountID;
revbudgetItem.InventoryID = thiskExt.UsrInventoryID;
revbudgetItem.CuryUnitRate = thiskExt.UsrUnitPrice;
revbudgetItem.Qty = thiskExt.UsrQuantity;
revbudgetItem.CuryAmount = thiskExt.UsrSellPrice;
revbudgetItem.UOM = invUOM;
revbudgetItem.RevisedQty = revbudgetItem.Qty;
revbudgetItem.CuryRevisedAmount = revbudgetItem.CuryAmount;
// --> Base.RevenueBudget.Update(revbudgetItem); <-- This works to update the cahce, but as soon as the user hits save, it reverts the changes back to 0.
}
}
I have tried it in the row persisting and persisted events but then get the
"Another process has added/updated record"
error which reverts everything. How can I get the values over and save it to the table when I hit the Save button?
Any help would be greatly appreciated.
So, the best solution to this we found so far is to update the Graph in the row persisted.
protected void PMProject_RowPersisted(PXCache cache, PXRowPersistedEventArgs e)
{
var row = (PMProject)e.Row;
if (e.TranStatus == PXTranStatus.Completed)
{
var target = PXGraph.CreateInstance<ProjectTaskEntry>();
var target2 = PXGraph.CreateInstance<ProjectEntry>();
//var target = PXGraph.CreateInstance<ProjectEntry>();
foreach (PMTask taskitem in Base.Tasks.Select())
{
PMTaskExt TaskExt = taskitem.GetExtension<PMTaskExt>();
target.Task.Update(taskitem);
foreach (PMRevenueBudget revbudgetItem in Base.RevenueBudget.Search<PMRevenueBudget.projectTaskID>(taskitem.TaskID))
{
revbudgetItem.Qty = TaskExt.UsrQuantity;
target2.RevenueBudget.Update(revbudgetItem);
}
}
target2.Save.PressButton();
}
}
Related
I am new to PUN2. I am facing an issue that I want to describe some betting amount for joining my room which I define at the time of room creation. The issue is that I want that amount must be shown to others when they are in a lobby, from where they could decide whether they join/not by paying that amount. For this I am doing:
I have 1 MenuManager.cs script in which
public InputField amount;
[SerializeField] Transform _content; //container of list
[SerializeField] RoomListing _roomListing;
List<RoomListing> _listings = new List<RoomListing>();
public int SetBetAmount()
{
if (string.IsNullOrEmpty(amount.text))
{
return -1;
}
else
return (int.Parse(amount.text));
}
// The Script that runs when Create Room Button Clicks as follow:
public void OnCreateRoomBtnClicked()
{
string roomName = "Room " + Random.Range(1, 800);
int maxPlayersInt = SetMaxPlayers();
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = (byte)maxPlayersInt;
string[] roomPropertiesInLobbby = { "betAmount" };
betAmount = SetBetAmount();
//customRoomProps["betAmount"] = (byte)SetBetAmount();
Debug.Log("Bet Amount Updated" + customRoomProps["betAmount"]);
SetLaps();
roomOptions.CustomRoomPropertiesForLobby = roomPropertiesInLobbby;
roomOptions.CustomRoomProperties = customRoomProps;
PhotonNetwork.CreateRoom(roomName, roomOptions);
}
OnRoomListUpdate Callback works fine for info data but not sending correct betAmount but the garbage value 0;
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
foreach (RoomInfo info in roomList)
{
if (info.RemovedFromList)
{
int index = _listings.FindIndex(x => x.RoomInfo.Name == info.Name);
if (index != -1)
{
Destroy(_listings[index].gameObject);
_listings.RemoveAt(index);
}
}
else
{
RoomListing listing = Instantiate(_roomListing, _content);
if (listing != null)
{
listing.GetComponent<RoomListing>().bettingAmt = -3; //there I tried betAmount but it sends 0
listing.SetRoomInfo(info);
_listings.Add(listing);
}
}
}
}
I have also tried this but not sure how to do this
public override void OnJoinedLobby()
{
//if (customRoomProps.ContainsKey("betAmount"))
//{
// //Debug.Log("Call From Master");
// object _amount;
// if (customRoomProps.TryGetValue("betAmount", out _amount))
// {
// Debug.Log("Bet Amount" + _amount.ToString());
// betAmountS = (int)_amount;
// Debug.Log("BetAmount " + betAmount);
// }
//}
//else
//{
// Debug.Log("Call From local");
//}
}
Plus, I have also tried PUNRPC but it works when others join the Room then they could see that data.
I don't have your entire code so I can only suspect what happens but my guess is the following:
The key is definitely added to the room properties otherwise it wouldn't return 0 but throw a KeyNotFoundException.
So from your given code I guess you somewhere have a predefined
private Hashtable customRoomProps = new Hashtable ();
private int betAmount;
and somewhere already set
customRoomProps ["betAmount"] = betAmount;
now when doing
betAmount = SetBetAmount();
you expect that the value is also updated within the customRoomProps.
BUT int is a value-type! The value you stored in the customRoomProps is a copy by value of whatever value was currently stored in betAmount the moment you added it.
The value stored in customRoomProps is in no way related to the betAmount anymore!
You rather need to set the value the moment you need it
betAmount = SetBetAmount();
customRoomProps["betAmount"] = betAmount;
basically the line you have commented out.
And then in OnRoomListUpdate you should be able to get it like
if(info.CustomProperties.TryGetValue("betAmount", out var betAmount))
{
listing.GetComponent<RoomListing>().bettingAmt = (int) betAmount;
}
I'm currently using a Timer to get text values from 4 values that are in a list of type ReadOnlyCollection. Is there a way to 'ADD' a listener to these 4 values to process the values when they change instead of using a Timer? Here is my current code in the Timer tick() event handler...
// Code in my Timer tick() method
for (int i = 0; i < stockWatchListTableRows.Count; i++)
{
if (i != 0 && i != 1 && i != stockWatchListTableRows.Count - 1)
{
row = stockWatchListTableRows[i];
// tds is a ReadOnlyCollection<IWebElement>
var tds = row.FindElements(By.TagName("span"));
string symbol = tds[0].GetAttribute("textContent");
string stock = tds[1].GetAttribute("textContent");
string price = tds[2].GetAttribute("textContent"); // NEED text changed event handler for this one the MOST, the other ones are secondary.
string change = tds[3].GetAttribute("textContent");
// get the existing price and see if the new price is greater or less than that
channelingStocksData csdata;
csdata = stockDictionary[symbol];
tblist = csdata.tbl;
string currentPrice = String.Empty;
string existingPrice = String.Empty;
bool bPriceIncreasing = true;
// get the textboxes for the current and support price
TextBox currentPriceTB = tblist[(int)TLPColumnNames.Current_Price];
// get the price before it increases
existingPrice = currentPriceTB.Text;
if (Convert.ToDouble(price) > Convert.ToDouble(existingPrice))
{
bPriceIncreasing = true;
}
else
{
bPriceIncreasing = false;
}
ScreenStockData(symbol, price, bPriceIncreasing);
}
}
I'm working on a multi-joystick setup where I need to build custom button mappings. And even map across devices. For example, if there is a separate joystick and throttle quadrant I need to map 'Z' or whatever, over to the throttle input. I also need to be able to check and see if there is a slider(s) available on each stick as I build the mapping profiles, etc. I cannot figure out how to just say something like:
if (joystick.HasSliders)
So far I've tried different variations of
PropertyInfo rxprop = typeof(SharpDX.DirectInput.JoystickState).GetProperty("Sliders");
However, if the joystick does not have sliders, this of course will throw an exception. If it only has a single slider, I will always get back an Int array of Sliders[] with two values, no matter if the stick only has a single slider or not. So it is not a guaranteed way to know if sliders exist, or even how many exist. If there is no second actual slider, the value Sliders[1] is always 0, but if there is a second slider it could still be in the 0 position.
Currently this is what I've been messing with:
usbjoysticks[k].Poll();
JoystickState currentState = null;
try
{
currentState = usbjoysticks[k].GetCurrentState();
//joystickmap.axisRangeMax = usbjoysticks[k].GetObjectInfoById(1);
PropertyInfo rxprop = typeof(SharpDX.DirectInput.JoystickState).GetProperty("Sliders");
var rzvalue = (int[])rxprop.GetValue(currentState, null);
var mySlider1 = rzvalue[0];
var datas = usbjoysticks[k].GetBufferedData();
foreach (var state in datas)
{
Console.WriteLine(state);
if (state.Offset == JoystickOffset.X)
{
Console.WriteLine(state.Value);
}
}
//DeviceObjectInstance my = usbjoysticks[k].GetObjectInfoByName("Sliders1");
var stuff = usbjoysticks[k].GetObjectPropertiesByName("Sliders0");
//=================
joystickmap.jX = "X";
joystickmap.axisRangeMax = usbjoysticks[k].GetObjectPropertiesByName("Y").Range.Maximum; //65535
joystickmap.jY = "Y";
if (currentState.Z != 0)
{
joystickmap.jZ = "Z";
var maxZrange = usbjoysticks[k].GetObjectPropertiesByName("Z").Range.Maximum;
joystickmap.axisRangeMax = usbjoysticks[k].GetObjectPropertiesByName("Z").Range.Maximum;
}
if (currentState.Sliders[0] != 0 || currentState.Sliders[1] != 0) //TODO possible change to Joystick State value in class object instead of text.
{
joystickmap.SLD1 = "Slider1";
//joystickmap.jZ = "Sliders";
joystickmap.jsSliders = currentState.Sliders;
var maxSld1range = usbjoysticks[k].GetObjectPropertiesByName("Sliders0").Range.Maximum;
joystickmap.sld1 = joystickmap.jsSliders[0];
joystickmap.sld2 = joystickmap.jsSliders[1];
}
if (currentState.Sliders[1] != 0)
{
joystickmap.SLD2 = "Slider2";
}
if (currentState.RotationX != 0)
{
joystickmap.rX = "RotationX";
}
if (currentState.RotationY != 0)
{
joystickmap.rY = "RotationY";
}
if (currentState.RotationZ != 0)
{
joystickmap.rZ = "RotationZ";
//joystickmap.jZ = "RotationZ";
}
joystickmap.axisdivider = 2;
for (var b = 0; b < 20; b++)
{
//joystickmap.joybuttons.Add(currentState.Buttons[b]);
joystickmap.joybuttons[b] = (b + 1);
}
joystickmappings.Add(joystickmap);
if (!File.Exists(filename))
{
File.WriteAllText(filename, JsonConvert.SerializeObject(joystickmap));
// serialize JSON directly to a file
using (StreamWriter file = File.CreateText(filename))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, joystickmap);
}
}
}
catch (Exception e)
{
MessageBox.Show("USB joystick map creation failure!\n" + e.Message);
break;
}
I'm using devexpress XtraGrid control. My problem is the following: I want to get the sum of the first column, and then the second column. I eventually want to subtract the sum of the first column of the sum of the second columns and to display the grid in the footer ...
Sum1Columns - Sum2Columns = balance
And then show balance on data grid control - footer (below the 1column)
dgvVIEW.Columns(1).Name = "PROMDUGU"
dgvVIEW.Columns(1).Caption = "1COLUMN"
dgvVIEW.Columns(1).Visible = True
dgvVIEW.Columns(1).DisplayFormat.FormatType = FormatType.Numeric
dgvVIEW.Columns(1).DisplayFormat.FormatString = "c2"
dgvVIEW.Columns(1).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Custom
dgvVIEW.Columns(1).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
dgvVIEW.Columns(1).SummaryItem.DisplayFormat = "SUM= {0:n2}"
dgvVIEW.Columns(2).Name = "PROMPOTR"
dgvVIEW.Columns(2).Caption = "2COLUMN"
dgvVIEW.Columns(2).Visible = True
dgvVIEW.Columns(2).DisplayFormat.FormatType = FormatType.Numeric
dgvVIEW.Columns(2).DisplayFormat.FormatString = "c2"
dgvVIEW.Columns(2).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
dgvVIEW.Columns(2).SummaryItem.DisplayFormat = "Sum= {0:n2}"
Add another summary field to 2nd column and set its type to custom.
dgvVIEW.Columns(2).Summary.Add(new GridColumnSummaryItem(SummaryItemType.Custom, "customBalance", "Balance= {0:c2}"));
Then handle CustomSummaryCalculate event.
private void dgvVIEW_CustomSummaryCalculate(object sender, CustomSummaryEventArgs e) {
if (e.SummaryProcess == CustomSummaryProcess.Start) {
this.sum1 = 0; // <--- class member !
this.sum2 = 0; // <--- class member !
return;
}
if (e.SummaryProcess == CustomSummaryProcess.Calculate) {
if (e.Item.FieldName == "PROMDUGU" {
this.sum1 += Convert.ToDecimal(e.FieldValue);
return;
}
if (e.Item.FieldName == "PROMPOTR" {
this.sum2 += Convert.ToDecimal(e.FieldValue);
return;
}
return;
}
if (e.SummaryProcess == CustomSummaryProcess.Finalize && e.Item.FieldName == "customBalance") {
e.TotalValue = sum1 - sum2;
}
}
So I have this datagridview that is linked to a Binding source that is binding to an underlying data table. The problem is I need to manual add rows to the datagridview.
This cannot be done while it is bound, so I have to work with the databinding.
If I add the rows to the underlying datatable, when the datatable is saved, the rows are duplicated, probably because the binding source somehow got a hold of a copy and inserted it also.
Adding it to the binding source is what I've been trying to do but it's not quite working.
Let me explain exactly what my setup is:
I have a database with two tables:
CashReceiptTable and CashReceiptItemsTable
CashReceiptItemsTable contains a FK to CashReceiptTable.
The form allows the users to add, and modify the two tables.
When the user enters a new cashreceipt, the cash receipt's id is -1, and the FK in cashReceiptitemstable is -1. When the database is saved, cashReceipt's id is updated, and I have to manually update cashreceiptitem's FK.
Here are the problems:
When I try to update the CashReceiptID (the FK) in more than one row in cashreceiteitems binding source, the first row is updated, and disappears (because it's filtered), and the other rows are removed, and I can no longer access them.
I have no idea why this is, I haven't updated the filter yet so they should still be there, but trying to access them throws RowNotInTableException.
I've managed a work around that copies the rows in the the binding source to an in memory array, deletes the first row in the binding source (all the other rows just vanish), update the row's FK and reinsert them into the binding source and save the table.
This works okay, but why do the rows disappear?
I also have one more slight problem. When the CashReceiptsTable is empty and I am adding a new row to it, if I add more than one row to the CashReceiptsItemTable it causes problems. When manually adding the items to the binding source, adding a new row pops to previous row off and pushes it onto the datatable. This hides it from my FK updating routine and it is lost, it also removes it from the DataGridView.
It only does that when I'm adding the first row to CashReceiptsTable. Why does it do this, and how can I fix it?
I'm posting my code that autopopulates it here:
private void autopopulate(decimal totalPayment) {
//remove old rows
for (int i = 0; i < tblCashReceiptsApplyToBindingSource.List.Count; i++) {
DataRowView viewRow = tblCashReceiptsApplyToBindingSource.List[i] as DataRowView;
RentalEaseDataSet.tblCashReceiptsApplyToRow row = viewRow.Row as RentalEaseDataSet.tblCashReceiptsApplyToRow;
if (row.CashReceiptsID == this.ReceiptID) {
tblCashReceiptsApplyToBindingSource.List.Remove(viewRow);
i--;
}
}
decimal payment = totalPayment;
//look for an exact amount
foreach (DataGridViewRow dueRow in dataViewDueRO.Rows) {
decimal due = -1 * (Decimal)dueRow.Cells[Due.Index].Value;
if (due == payment) {
String charge = (String)dueRow.Cells[Description.Index].Value;
int chargeID = ManageCheckbooks.findTransactionID(charge);
tblCashReceiptsApplyToBindingSource.AddNew();
RentalEaseDataSet.tblCashReceiptsApplyToRow row = ((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row as RentalEaseDataSet.tblCashReceiptsApplyToRow;
row.CashReceiptsID = this.ReceiptID;
row.ApplyTo = chargeID;
row.Paid = payment; //convert to positive
payment = 0;
break;
}
}
//if the exact amount was found, payment will = 0, and this will do nothing, otherwise,
//divy out everything left over (which will be everything)
foreach (DataGridViewRow dueRow in dataViewDueRO.Rows) {
String charge = (String)dueRow.Cells[Description.Index].Value;
decimal due = (Decimal)dueRow.Cells[Due.Index].Value;
if (due > 0 || payment <= 0) {
continue;
}
int chargeID = ManageCheckbooks.findTransactionID(charge);
payment += due; //due is negative, so this will subtract how much the user owes
tblCashReceiptsApplyToBindingSource.AddNew();
RentalEaseDataSet.tblCashReceiptsApplyToRow row = ((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row as RentalEaseDataSet.tblCashReceiptsApplyToRow;
row.CashReceiptsID = this.ReceiptID;
row.ApplyTo = chargeID;
if (payment >= 0) {
//payment is enough to cover this
row.Paid = due * -1; //convert to positive
} else {
//doesn't have enough money to conver this, can only cover partial, or none
row.Paid = (due - payment) * -1; //math:
//money remaining $50, current charge = $60
//payment = 50 + -60 = -10
//row["Paid"] = (-60 - -10) * -1
//row["Paid"] = (-60 + 10) * -1
//row["Paid"] = -50 * -1
//row["Paid"] = 50
}
if (payment <= 0) {
break; //don't conintue, no more money to distribute
}
}
isVirginRow = true;
}
And this is the function that saves it to the database:
protected override void saveToDatabase() {
tblCashReceiptsBindingSource.EndEdit();
isVirginRow = false;
RentalEaseDataSet.tblCashReceiptsRow[] rows = rentalEaseDataSet.tblCashReceipts.Select("ID < 0") as RentalEaseDataSet.tblCashReceiptsRow[];
int newID = -1;
if (rows.Count() > 0) {
tblCashReceiptsTableAdapter.Update(rows[0]);
newID = rows[0].ID;
}
tblCashReceiptsTableAdapter.Update(rentalEaseDataSet.tblCashReceipts);
//update table
/*foreach (RentalEaseDataSet.tblCashReceiptsApplyToRow row in rentalEaseDataSet.tblCashReceiptsApplyTo.Select("CashReceiptsID = -1")) {
row.CashReceiptsID = newID;
}*/
//update binding source
DataRowView[] applicationsOld = new DataRowView[tblCashReceiptsApplyToBindingSource.List.Count];
RentalEaseDataSet.tblCashReceiptsApplyToRow[] applicationsNew = new RentalEaseDataSet.tblCashReceiptsApplyToRow[tblCashReceiptsApplyToBindingSource.List.Count];
tblCashReceiptsApplyToBindingSource.List.CopyTo(applicationsOld, 0);
for (int i = 0; i < applicationsOld.Count(); i++) {
RentalEaseDataSet.tblCashReceiptsApplyToRow row = applicationsOld[i].Row as RentalEaseDataSet.tblCashReceiptsApplyToRow;
if (row.CashReceiptsID < 0) {
applicationsNew[i] = rentalEaseDataSet.tblCashReceiptsApplyTo.NewRow() as RentalEaseDataSet.tblCashReceiptsApplyToRow;
applicationsNew[i]["ID"] = row.ID;
applicationsNew[i]["CashReceiptsID"] = this.ReceiptID;
applicationsNew[i][2] = row[2];
applicationsNew[i][3] = row[3];
applicationsNew[i][4] = row[4];
//row.Delete();
}
}
for (int i = 0; i < applicationsOld.Count(); i++) {
try {
if ((int)applicationsOld[i].Row["ID"] < 0) {
applicationsOld[i].Row.Delete();
}
} catch (RowNotInTableException) {
break;
}
}
this.tblCashReceiptsApplyToBindingSource.Filter = "CashReceiptsID = " + this.ReceiptID;
foreach (DataRow newRow in applicationsNew) {
if (newRow == null) {
break;
}
tblCashReceiptsApplyToBindingSource.AddNew();
((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row[0] = newRow[0];
((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row[1] = newRow[1];
((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row[2] = newRow[2];
((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row[3] = newRow[3];
((DataRowView)tblCashReceiptsApplyToBindingSource.Current).Row[4] = newRow[4];
}
tblCashReceiptsApplyToBindingSource.EndEdit();
checkForBadRows();
tblCashReceiptsApplyToTableAdapter.Update(rentalEaseDataSet.tblCashReceiptsApplyTo);
tblCashReceiptsApplyToTableAdapter.Fill(rentalEaseDataSet.tblCashReceiptsApplyTo);
}
You might want to try adding rows to the DataGridView. Since you are binding to it, the DataGridView becomes your 'access point'.
I've got several applications that bind to DataGridView and for most circumstances when I add a row I do so through the DataGridView. It already has properties/methods/events that let you add with relative ease.
If you need some more information I can update.